package com.erp.erp_ui.business.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.erp.enums.ModuleTypeEnum;
import com.erp.enums.OperationStatusEnum;
import com.erp.enums.OperationTypeEnum;
import com.erp.erp_entitys.BillExchangeInfo.BillExchangeInfo;
import com.erp.erp_entitys.User.UserEntity;
import com.erp.erp_entitys.bill_declare.BillDeclareInfo;
import com.erp.erp_entitys.business.entity.*;
import com.erp.erp_entitys.business.req.*;
import com.erp.erp_entitys.business.rsp.*;
import com.erp.erp_entitys.log.entity.DataInfoLogEntity;
import com.erp.erp_entitys.money.entity.PaymentDetailEntity;
import com.erp.erp_entitys.warehouse.entity.AnnexEntity;
import com.erp.erp_entitys.warehouse.entity.StockEntity;
import com.erp.erp_entitys.warehouse.entity.TempAnnexEntity;
import com.erp.erp_entitys.warehouse.req.StockReq;
import com.erp.erp_servers.bill_declare.BillDeclareInfoService;
import com.erp.erp_servers.bill_exchange.BillExchangeInfoService;
import com.erp.erp_servers.business.*;
import com.erp.erp_servers.log.IDataInfoLogService;
import com.erp.erp_servers.money.IPaymentDetailService;
import com.erp.erp_servers.money.IPaymentService;
import com.erp.erp_servers.warehouse.IAnnexService;
import com.erp.erp_servers.warehouse.ISellOutStockService;
import com.erp.erp_servers.warehouse.IStockService;
import com.erp.erp_servers.warehouse.ITempAnnexService;
import com.erp.erp_ui.business.req.*;
import com.erp.erp_ui.business.vo.*;
import com.erp.erp_ui.money.req.OperationReq;
import com.erp.erp_ui.warehouse.enums.DataIsValidEnum;
import com.erp.erp_ui.warehouse.req.AnnexReq;
import com.erp.erp_ui.warehouse.vo.AnnexVo;
import com.erp.utils.*;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName : CarryDetailService
 * @Description : 出运明细业务逻辑层
 * @Author : lst
 * @Date: 2020-06-27 14:07
 */
@Service
public class CarryDetailService {

    /**
     * 日志
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(CarryDetailService.class);

    /**
     * 出运明细接口
     */
    private final ICarryDetailService carryDetailService;

    /**
     * 出运明细子表接口
     */
    private final ICarryDetailProductService carryDetailProductService;

    /**
     * 出运明细产品配件接口
     */
    private final ICarryDetailProductPartsService carryDetailProductPartsService;

    /**
     * 出运明细费用接口
     */
    private final ICarryDetailCostService carryDetailCostService;

    /**
     * 附件接口
     */
    private final IAnnexService annexService;

    /**
     * 临时附件接口
     */
    private final ITempAnnexService tempAnnexService;

    /**
     * 外销主表接口
     */
    private final IExportContractService exportContractService;

    /**
     * 报关接口
     */
    private final BillDeclareInfoService billDeclareInfoService;

    /**
     * 结汇接口
     */
    private final BillExchangeInfoService billExchangeInfoService;

    /**
     * 付款接口
     */
    private final IPaymentService paymentService;

    /**
     * 付款明细接口
     */
    private final IPaymentDetailService paymentDetailService;

    /**
     * 销售出库接口
     */
    private final ISellOutStockService sellOutStockService;

    /**
     * 操作日志信息接口
     */
    private final IDataInfoLogService dataInfoLogService;

    /**
     * 外销产品接口
     */
    private final IExportContractProductService exportContractProductService;

    /**
     * 任务产品明细接口
     */
    private final ITaskProductService taskProductService;

    /**
     * 库存接口
     */
    private final IStockService stockService;


    @Autowired
    public CarryDetailService(ICarryDetailService carryDetailService,
                              ICarryDetailProductService carryDetailProductService,
                              ICarryDetailProductPartsService carryDetailProductPartsService,
                              ICarryDetailCostService carryDetailCostService,
                              IAnnexService annexService,
                              ITempAnnexService tempAnnexService,
                              IExportContractService exportContractService,
                              BillDeclareInfoService billDeclareInfoService,
                              BillExchangeInfoService billExchangeInfoService,
                              IPaymentService paymentService,
                              IPaymentDetailService paymentDetailService,
                              ISellOutStockService sellOutStockService,
                              IDataInfoLogService dataInfoLogService,
                              IExportContractProductService exportContractProductService,
                              ITaskProductService taskProductService,
                              IStockService stockService) {
        this.carryDetailService = carryDetailService;
        this.carryDetailProductService = carryDetailProductService;
        this.carryDetailProductPartsService = carryDetailProductPartsService;
        this.carryDetailCostService = carryDetailCostService;
        this.annexService = annexService;
        this.tempAnnexService = tempAnnexService;
        this.exportContractService = exportContractService;
        this.billDeclareInfoService = billDeclareInfoService;
        this.billExchangeInfoService = billExchangeInfoService;
        this.paymentService = paymentService;
        this.paymentDetailService = paymentDetailService;
        this.sellOutStockService = sellOutStockService;
        this.dataInfoLogService = dataInfoLogService;
        this.exportContractProductService = exportContractProductService;
        this.taskProductService = taskProductService;
        this.stockService = stockService;
    }

    /**
     * 分页查询
     *
     * @param req 查询参数
     * @return 分页信息
     */
    public PageInfo<CarryDetailPageListVo> getListByPage(CarryDetailPageListReq req) {
        //初始化回参对象集合
        List<CarryDetailPageListVo> voList = new ArrayList<>();
        if (StringUtils.isBlank(req.getOperationCode()) && StringUtils.isBlank(req.getSalesmanCode()) && StringUtils.isBlank(req.getDeptSalesmanCode()) && StringUtils.isBlank(req.getDeptOperationCode())){
            PageInfo pageInfo = new PageInfo();
            pageInfo.setList(voList);
            return pageInfo;
        }
        //初始化查询对象
        CarryDetailPageListInfoReq query = new CarryDetailPageListInfoReq();
        //赋值
        BeanUtils.copyProperties(req, query);
        if(StringUtils.isNotEmpty(req.getBillNo())){
            //去掉前后空格
            query.setBillNo(req.getBillNo().trim());
        }
        if(StringUtils.isNotEmpty(req.getProductCode())){
            //去掉前后空格
            query.setProductCode(req.getProductCode().trim());
        }
        if(StringUtils.isNotEmpty(req.getSpecNo())){
            //去掉前后空格
            query.setSpecNo(req.getSpecNo().trim());
        }
        if(StringUtils.isNotEmpty(req.getLotNo())){
            //去掉前后空格
            query.setLotNo(req.getLotNo().trim());
        }
        //调用接口查询结果
        List<CarryDetailEntity> carryList = carryDetailService.getCarryDetailPageList(query);
        PageInfo pageInfo = new PageInfo(carryList);
        if (CollectionUtils.isEmpty(carryList)) {
            pageInfo.setList(voList);
            return pageInfo;
        }
        for (CarryDetailEntity carry : carryList) {
            CarryDetailPageListVo vo = new CarryDetailPageListVo();
            //赋值
            BeanUtils.copyProperties(carry, vo);
            //出运日期
            vo.setTime(DateUtils.format(carry.getTime(), DateUtils.DATE_PATTERN));
            //货号日期
            vo.setArticleNumberDate(DateUtils.format(carry.getArticleNumberDate(), DateUtils.DATE_PATTERN));
            //实际开船日期
            vo.setActualTimeDismissal(DateUtils.format(carry.getActualTimeDismissal(), DateUtils.DATE_PATTERN));
            //进仓装柜日期
            vo.setLoadingTime(DateUtils.format(carry.getLoadingTime(), DateUtils.DATE_PATTERN));
            //制单日期
            vo.setCreateDate(DateUtils.format(carry.getCreateDate()));
            //状态
            vo.setStatusStr(OperationStatusEnum.getDescById(carry.getStatus()));

            voList.add(vo);
        }

        pageInfo.setList(voList);
        return pageInfo;
    }

    /**
     * 删除
     *
     * @param req
     */
    public void delete(OperationReq req) {
        if (null == req.getId() || null == req.getStatus()) {
            return;
        }
        CarryDetailEntity contractReq = new CarryDetailEntity();
        contractReq.setId(req.getId());
        contractReq.setModifyTime(new Date());
        if (req.getStatus().equals(OperationStatusEnum.DRAFT_BOX.getId())) {
            //草稿箱删除,数位改为垃圾箱
            contractReq.setStatus(OperationStatusEnum.TRASH_CAN.getId());
            carryDetailService.update(contractReq);
            return;
        } else {
            //垃圾箱删除,将主数据设为无效
            contractReq.setValid(DataIsValidEnum.INVALID.getId());
            carryDetailService.update(contractReq);
        }
        //获取对应明细数据
        CarryDetailProductEntity detailEntity = new CarryDetailProductEntity();
        detailEntity.setCarryDetailId(req.getId());
        detailEntity.setValid(DataIsValidEnum.VALID.getId());

        List<CarryDetailProductEntity> detailList = carryDetailProductService.queryAll(detailEntity);
        if (CollectionUtils.isEmpty(detailList)) {
            return;
        }
        //将所有对应有效的明细数据设为无效
        for (CarryDetailProductEntity detail : detailList) {
            CarryDetailProductEntity detailReq = new CarryDetailProductEntity();
            detailReq.setId(detail.getId());
            detailReq.setValid(DataIsValidEnum.INVALID.getId());

            carryDetailProductService.update(detailReq);
        }

        //获取费用数据
        CarryDetailCostEntity costEntity = new CarryDetailCostEntity();
        costEntity.setParentId(req.getId());
        costEntity.setValid(DataIsValidEnum.VALID.getId());

        List<CarryDetailCostEntity> costList = carryDetailCostService.queryAll(costEntity);
        if (CollectionUtils.isEmpty(costList)) {
            return;
        }
        //将所有对应有效的费用数据设为无效
        for (CarryDetailCostEntity cost : costList) {
            CarryDetailCostEntity costReq = new CarryDetailCostEntity();
            costReq.setId(cost.getId());
            costReq.setValid(DataIsValidEnum.INVALID.getId());

            carryDetailCostService.update(costReq);
        }

        //获取对应所有附件
        AnnexEntity annex = new AnnexEntity();
        annex.setModuleId(ModuleTypeEnum.BUSINESS_TASK.getId());
        annex.setParentId(req.getId());
        annex.setValid(DataIsValidEnum.VALID.getId());
        List<AnnexEntity> annexList = annexService.queryAll(annex);
        if (CollectionUtils.isEmpty(annexList)) {
            return;
        }
        //删除所有对应的有效的附件
        for (AnnexEntity annexData : annexList) {
            AnnexEntity annexReq = new AnnexEntity();
            annexReq.setId(annexData.getId());
            annexReq.setUpdateTime(new Date());
            annexReq.setValid(DataIsValidEnum.INVALID.getId());

            annexService.update(annexReq);
        }
    }

    /**
     * 箱体操作
     *
     * @param req
     */
    public R operation(OperationReq req, UserEntity user) {
        if (null == req.getId() || null == req.getOperation() || null == req.getBillNo()) {
            return R.buildError(ResultStatusEnum.SYSTEM_ERROR);
        }
        CarryDetailEntity queryReq = new CarryDetailEntity();
        //设置修改主键
        queryReq.setId(req.getId());
        //修改时间
        queryReq.setModifyTime(new Date());

        //新增日志信息
        DataInfoLogEntity dataInfoLog = new DataInfoLogEntity();
        //模块主表id
        dataInfoLog.setParentId(req.getId());
        //模块id
        dataInfoLog.setModuleId(ModuleTypeEnum.BUSINESS_CARRY_DETAIL.getId());
        //操作人编码
        dataInfoLog.setOperationCode(user.getCode());
        //操作人名称
        dataInfoLog.setOperationName(user.getName());
        //操作时间
        dataInfoLog.setOperationTime(new Date());
        //操作内容
        dataInfoLog.setOperationContent("单据操作");

        switch (req.getOperation()) {
            case 1:
                //提交审批后,状态直接为已批箱
            case 2:
                //审批通过,状态设为已批箱,对应数据量的增减
                queryReq.setStatus(OperationStatusEnum.APPROVED_BOX.getId());
                //操作类型
                dataInfoLog.setOperationType(OperationTypeEnum.APPROVED_DATA.getId());
                break;
            case 3:
                //审批退回后修改状态,对应数据量的回退
                //校验数据是否被调用
                int result = checkDataIsUsed(req.getBillNo());
                if (0 == result) {
                    //状态设为草稿箱
                    queryReq.setStatus(OperationStatusEnum.DRAFT_BOX.getId());
                    //操作类型
                    dataInfoLog.setOperationType(OperationTypeEnum.APPROVAL_RETURNED_DATA.getId());
                } else if (1 == result) {
                    //报关调用
                    return R.buildError(ResultStatusEnum.SHIPMENT_BILL_DECLARE_USED);
                } else if (2 == result) {
                    //结汇调用
                    return R.buildError(ResultStatusEnum.SHIPMENT_BILL_EXCHANGE_USED);
                } else if (3 == result) {
                    //付款调用
                    return R.buildError(ResultStatusEnum.SHIPMENT_PAYMENT_USED);
                }
                break;
            case 4:
                //将状态设为完成
                queryReq.setStatus(OperationStatusEnum.COMPLETION_BOX.getId());
                //操作类型
                dataInfoLog.setOperationType(OperationTypeEnum.CONSUMMATION_DATA.getId());
                break;
            case 5:
                //点击还原，将状态改为草稿箱
                queryReq.setStatus(OperationStatusEnum.DRAFT_BOX.getId());
                break;
            case 6:
                //点击终止，将状态改为终止箱
                //校验是否可以终止数据1:付款调用 0:没有被调用
                Integer usedStatus = checkDataIsTermination(req.getBillNo());
                switch (usedStatus){
                    case 0:
                        //状态设为终止箱
                        queryReq.setStatus(OperationStatusEnum.TERMINATION_BOX.getId());
                        //操作类型
                        dataInfoLog.setOperationType(OperationTypeEnum.STOP_DATA.getId());
                        break;
                    case 1:
                        //付款调用
                        return R.buildError(ResultStatusEnum.PAYMENT_USED);
                }
                break;
            case 7:
                //取消终止，将状态改为已批箱
                queryReq.setStatus(OperationStatusEnum.APPROVED_BOX.getId());
                break;
        }
        //调用接口修改
        carryDetailService.update(queryReq);

        dataInfoLogService.insert(dataInfoLog);

        return R.buildError(ResultStatusEnum.SUCCESS);
    }

    /**
     * 校验是否可以终止数据1:付款调用 0:没有被调用
     * @param billNo 明细单号
     * @return 1:付款调用 0:没有被调用
     */
    private int checkDataIsTermination(String billNo){
        //获取已做付款数量
        int count = paymentService.getCountByCarryDetailBillNoOrProductId(billNo, null);
        if (count == 0) {
            return 0;
        } else {
            return 1;
        }
    }

    /**
     * 校验该出运明细是否被下游(报关、结汇、付款)调用
     * 0:未调用 1:报关调用 2:结汇调用 3:付款调用
     *
     * @param shipmentDetailNo 出运明细单号
     * @return
     */
    public int checkDataIsUsed(String shipmentDetailNo) {
        if (StringUtils.isEmpty(shipmentDetailNo)) {
            return 0;
        }
        //获取报关信息
        List<BillDeclareInfo> billDeclareInfos = billDeclareInfoService.checkBillNo(shipmentDetailNo);
        if (!CollectionUtils.isEmpty(billDeclareInfos)) {
            return 1;
        }
        //获取结汇信息
        List<BillExchangeInfo> billExchangeInfos = billExchangeInfoService.checkBillNo(shipmentDetailNo);
        if (!CollectionUtils.isEmpty(billExchangeInfos)) {
            return 2;
        }
        //获取付款信息
        PaymentDetailEntity paymentDetailReq = new PaymentDetailEntity();
        //出运发票号
        paymentDetailReq.setInvoiceNumber(shipmentDetailNo);
        //数据有效
        paymentDetailReq.setValid(DataIsValidEnum.VALID.getId());
        List<PaymentDetailEntity> detailEntities = paymentDetailService.queryAll(paymentDetailReq);
        if (!CollectionUtils.isEmpty(detailEntities)) {
            return 3;
        }
        return 0;
    }

    /**
     * 校验产品数据是否被调用
     * @param productCode 产品编码
     * @param specNo 规格编码
     * @return 0:未调用 1:外销调用 2:备货调用 3:采购调用 4:库存调用
     */
    public int checkProductIsUsed(String productCode, String specNo) {
        //获取外销
        ExportContractProductEntity contractReq = new ExportContractProductEntity();
        contractReq.setProductCode(productCode);
        contractReq.setSpecificationCode(specNo);
        contractReq.setValid(DataIsValidEnum.VALID.getId());
        List<ExportContractProductEntity> exportContractProductList = exportContractProductService.queryAll(contractReq);
        if (!CollectionUtils.isEmpty(exportContractProductList)) {
            return 1;
        }

        //获取备货信息
        TaskProductEntity taskProductReq = new TaskProductEntity();
        taskProductReq.setProductCode(productCode);
        taskProductReq.setSpecificationCode(specNo);
        taskProductReq.setValid(DataIsValidEnum.VALID.getId());
        List<TaskProductEntity> taskProductList = taskProductService.queryAll(taskProductReq);
        if (!CollectionUtils.isEmpty(taskProductList)) {
            return 2;
        }

        //获取采购信息
        BigDecimal usedProductSum = carryDetailService.getUsedProductSumInPurchase(productCode, specNo);
        if (usedProductSum.compareTo(BigDecimal.ZERO) == 1) {
            return 3;
        }

        //获取库存信息(实际数量大于零)
        StockReq stockReq = new StockReq();
        stockReq.setLikeProductCode(1);
        stockReq.setProductCode(productCode);
        stockReq.setLikeSpecificationCode(1);
        stockReq.setSpecificationCode(specNo);
        //实际数量大于零
        stockReq.setZeroStock(0);
        List<StockEntity> stockList = stockService.getStockList(stockReq);
        if (!CollectionUtils.isEmpty(stockList)) {
            return 4;
        }
        return 0;
    }

    /**
     * 批量操作
     * @param req 操作数据实体
     * @return 批量操作结果
     */
    public R batchOperation(BatchOperationReq req){
        if(CollectionUtils.isEmpty(req.getOperationReqs())){
            return R.buildError(ResultStatusEnum.SUCCESS);
        }
        switch (req.getType()){
            case 1:
                for(OperationReq operationReq : req.getOperationReqs()){
                    if(OperationStatusEnum.APPROVED_BOX.getId() == operationReq.getStatus()){
                        CarryDetailEntity info = new CarryDetailEntity();
                        //设置修改主键
                        info.setId(operationReq.getId());
                        //修改时间
                        info.setModifyTime(new Date());
                        //一键关账后，数据由已批改为完成
                        info.setStatus(OperationStatusEnum.COMPLETION_BOX.getId());
                        //调用接口修改
                        carryDetailService.update(info);
                    }
                }
                break;
            case 2:
                for(OperationReq operationReq : req.getOperationReqs()){
                    if(OperationStatusEnum.COMPLETION_BOX.getId() == operationReq.getStatus()){
                        CarryDetailEntity info = new CarryDetailEntity();
                        //设置修改主键
                        info.setId(operationReq.getId());
                        //修改时间
                        info.setModifyTime(new Date());
                        //一键取消，数据由完成改为已批
                        info.setStatus(OperationStatusEnum.APPROVED_BOX.getId());
                        //调用接口修改
                        carryDetailService.update(info);
                    }
                }
                break;
            default:
                break;
        }
        return R.buildError(ResultStatusEnum.SUCCESS);
    }


    /**
     * 导入出运计划信息
     *
     * @param req 查询条件
     * @return 出运计划信息
     */
    public PageInfo<ImportCarryPlanVo> getShipmentPlanInfo(ImportCarryPlanReq req) {
        //初始化查询对象
        ImportCarryPlanInfoReq queryReq = new ImportCarryPlanInfoReq();
        //赋值
        BeanUtils.copyProperties(req, queryReq);
        if(StringUtils.isNotEmpty(req.getShipmentNo())){
            //出运编号去掉前后空格
            queryReq.setShipmentNo(req.getShipmentNo());
        }
        if(StringUtils.isNotEmpty(req.getCustomerContractNo())){
            //客户合同号去掉前后空格
            queryReq.setCustomerContractNo(req.getCustomerContractNo());
        }
        if(StringUtils.isNotEmpty(req.getSalesContractNo())){
            //合同编号去掉前后空格
            queryReq.setSalesContractNo(req.getSalesContractNo());
        }
        //调用接口获取结果
        List<ImportCarryPlanInfoRsp> carryPlanList = carryDetailService.getShipmentPlanInfo(queryReq);
        return getCarryPlanInfo(carryPlanList);
    }


    /**
     * 导出运计划产品关联验货信息
     *
     * @param id 出运计划id
     * @return 出运计划产品关联验货信息
     */
    public List<ImportCarryPlanProductVo> importCarryPlanProduct(Integer id) {
        //初始化回参对象集合
        List<ImportCarryPlanProductVo> vo = new ArrayList<>();
        if (null == id) {
            return vo;
        }
        //1.获取出运计划主表信息
        CarryPlanInfoRsp planInfo = carryDetailService.getCarryPlanById(id);
        CarryPlanInfoVo planInfoVo = new CarryPlanInfoVo();
        //赋值
        BeanUtils.copyProperties(planInfo, planInfoVo);
        //设置出运日期
        planInfoVo.setTime(DateUtils.format(planInfo.getTime()));
        //设置货号日期
        planInfoVo.setArticleNumberDate(DateUtils.format(planInfo.getArticleNumberDate()));

        //2.获取出运计划费用信息
        List<ImportPlanCostInfoRsp> costInfos = carryDetailService.getCarryPlanCostInfo(id);
        List<ImportPlanCostInfoVo> costList = new ArrayList<>();
        for (ImportPlanCostInfoRsp costInfoRsp : costInfos) {
            //初始化费用回参实体
            ImportPlanCostInfoVo costVo = new ImportPlanCostInfoVo();
            //字段赋值
            BeanUtils.copyProperties(costInfoRsp, costVo);

            costList.add(costVo);
        }

        //3.获取对应附件信息
        List<ImportCarryPlanAnnexRsp> annexRspList = carryDetailService.getCarryPlanAnnexInfo(id);
        List<AnnexVo> annexList = new ArrayList<>();
        for (ImportCarryPlanAnnexRsp annexRsp : annexRspList) {
            AnnexVo annexVo = new AnnexVo();
            BeanUtils.copyProperties(annexRsp, annexVo);
            //日期转换
            annexVo.setUploadTime(DateUtils.format(annexRsp.getUploadTime(), DateUtils.DATE_TIME_PATTERN));

            annexList.add(annexVo);
        }

        //4.获取产品信息
        List<ImportCarryPlanProductInfoRsp> products = carryDetailService.getCarryPlanProductByParentId(id);
        if (CollectionUtils.isEmpty(products)) {
            return vo;
        }
        for (ImportCarryPlanProductInfoRsp infoRsp : products) {
            //初始化回参实体
            ImportCarryPlanProductVo productVo = new ImportCarryPlanProductVo();
            //赋值
            BeanUtils.copyProperties(infoRsp, productVo);
            //设置出运明细回显主表信息数据
            productVo.setCarryPlanInfo(planInfoVo);
            //设置出运计划费用信息
            productVo.setCostList(costList);
            //设置对应附件信息
            productVo.setAnnexList(annexList);

            //统计指定出运单号、销售合同号、产品编码、规格编码在出运明细中的数量
            ImportPlanRemainingQuantityReq req = new ImportPlanRemainingQuantityReq();
            //设置出运明细号
            req.setBillNo(planInfo.getCarryPlanNo());
            //设置外销合同号
            req.setContractNo(infoRsp.getSaleContractNo());
            //设置产品编码
            req.setProductCode(infoRsp.getProductCode());
            //设置规格编码
            req.setSpecificationCode(infoRsp.getSpecNo());
            BigDecimal sum = getRemainingQuantity(req);
            //剩余数量=库存数量-被调用数量
            BigDecimal productNum = new BigDecimal("0");
            if (StringUtil.isNotEmpty(infoRsp.getProductNum())) {
                productNum = infoRsp.getProductNum();
            }
            BigDecimal remainingQuantity = productNum.subtract(sum);
            if (remainingQuantity.compareTo(BigDecimal.ZERO) < 1) {
                //剩余数量小于等于零，该产品无法再被调用
                continue;
            }
            //设置剩余数量
            productVo.setRemainingQuantity(remainingQuantity);
            //剩余数量默认等于本次出运数量
            productVo.setProductNum(remainingQuantity);

            //获取对应配件信息
            List<ImportCarryPlanPartsRsp> planParts = carryDetailService.getCarryPlanPartsInfo(id, infoRsp.getProductId());
            //初始化配件回参对象
            List<ImportCarryPlanPartsVo> partsList = new ArrayList<>();
            //配件成本 = SUM(配件的成本单价)
            BigDecimal accessoriesCost = new BigDecimal("0");
            if (!CollectionUtils.isEmpty(planParts)) {
                for (ImportCarryPlanPartsRsp planPartsRsp : planParts) {
                    ImportCarryPlanPartsVo partsVo = new ImportCarryPlanPartsVo();
                    //赋值
                    BeanUtils.copyProperties(planPartsRsp, partsVo);
                    //采购单号
                    partsVo.setPurchaseNo(planPartsRsp.getContractPurchaseNumber());
                    if(StringUtil.isNotEmpty(planPartsRsp.getCostUnitPrice())){
                        accessoriesCost = accessoriesCost.add(planPartsRsp.getCostUnitPrice());
                    }

                    partsList.add(partsVo);
                }
            }
            productVo.setPartsList(partsList);
            //配件成本
            productVo.setAccessoriesCost(accessoriesCost);
            //成品成本
            BigDecimal finishedProductCost = new BigDecimal("0");
            if(StringUtil.isNotEmpty(infoRsp.getFinishedProductCost())){
                finishedProductCost = infoRsp.getFinishedProductCost();
            }
            //成本单价 = 成品成本 + 配件成本
            BigDecimal costUnitPrice = finishedProductCost.add(accessoriesCost);
            productVo.setCostUnitPrice(costUnitPrice);

            vo.add(productVo);
        }
        return vo;
    }

    /**
     * 导入-出运计划主表关联调拨信息
     *
     * @param req 查询条件
     * @return 出运计划信息
     */
    public PageInfo<ImportCarryPlanVo> importCarryPlanAssociateTransferByPage(ImportCarryPlanInfoReq req) {
        if(StringUtils.isNotEmpty(req.getShipmentNo())){
            //出运编号去掉前后空格
            req.setShipmentNo(req.getShipmentNo());
        }
        if(StringUtils.isNotEmpty(req.getCustomerContractNo())){
            //客户合同号去掉前后空格
            req.setCustomerContractNo(req.getCustomerContractNo());
        }
        if(StringUtils.isNotEmpty(req.getSalesContractNo())){
            //合同编号去掉前后空格
            req.setSalesContractNo(req.getSalesContractNo());
        }
        //调用接口获取结果
        List<ImportCarryPlanInfoRsp> carryPlanList = carryDetailService.importCarryPlanAssociateTransfer(req);
        return getCarryPlanInfo(carryPlanList);
    }

    /**
     * 获取出运计划信息
     *
     * @param carryPlanList 出运计划信息
     * @return 出运计划信息
     */
    private PageInfo getCarryPlanInfo(List<ImportCarryPlanInfoRsp> carryPlanList) {
        //获取分页信息
        PageInfo pageInfo = new PageInfo(carryPlanList);
        //初始化回参对象集合
        List<ImportCarryPlanVo> voList = new ArrayList<>();
        if (CollectionUtils.isEmpty(carryPlanList)) {
            pageInfo.setList(voList);
            return pageInfo;
        }
        for (ImportCarryPlanInfoRsp planInfo : carryPlanList) {
            ImportCarryPlanVo vo = new ImportCarryPlanVo();
            BeanUtils.copyProperties(planInfo, vo);
            //签约日期
            vo.setSigningDate(DateUtils.format(planInfo.getSigningDate(), DateUtils.DATE_PATTERN));
            //货好日期
            vo.setDeliveryDate(DateUtils.format(planInfo.getDeliveryDate(), DateUtils.DATE_PATTERN));
            //出运日期
            vo.setCarryDate(DateUtils.format(planInfo.getCarryDate(), DateUtils.DATE_PATTERN));

            voList.add(vo);
        }

        pageInfo.setList(voList);
        return pageInfo;
    }

    /**
     * 出运计划主表关联调拨信息
     *
     * @param id 出运计划id
     * @return 出运计划主表关联调拨信息
     */
    public List<ImportCarryPlanProductVo> importCarryPlanProductAssociateTransfer(Integer id) {
        //初始化回参对象集合
        List<ImportCarryPlanProductVo> vo = new ArrayList<>();
        if (null == id) {
            return vo;
        }
        //1.获取出运计划主表信息
        CarryPlanInfoRsp planInfo = carryDetailService.queryCarryPlanInfoById(id);
        CarryPlanInfoVo planInfoVo = new CarryPlanInfoVo();
        //赋值
        BeanUtils.copyProperties(planInfo, planInfoVo);
        //设置出运日期
        planInfoVo.setTime(DateUtils.format(planInfo.getTime()));
        //设置货号日期
        planInfoVo.setArticleNumberDate(DateUtils.format(planInfo.getArticleNumberDate()));

        //2.获取出运计划费用信息
        List<ImportPlanCostInfoRsp> costInfos = carryDetailService.getCarryPlanCostInfo(id);
        List<ImportPlanCostInfoVo> costList = new ArrayList<>();
        for (ImportPlanCostInfoRsp costInfoRsp : costInfos) {
            //初始化费用回参实体
            ImportPlanCostInfoVo costVo = new ImportPlanCostInfoVo();
            //字段赋值
            BeanUtils.copyProperties(costInfoRsp, costVo);

            costList.add(costVo);
        }

        //3.获取对应附件信息
        List<ImportCarryPlanAnnexRsp> annexRspList = carryDetailService.getCarryPlanAnnexInfo(id);
        List<AnnexVo> annexList = new ArrayList<>();
        for (ImportCarryPlanAnnexRsp annexRsp : annexRspList) {
            AnnexVo annexVo = new AnnexVo();
            BeanUtils.copyProperties(annexRsp, annexVo);
            //日期转换
            annexVo.setUploadTime(DateUtils.format(annexRsp.getUploadTime(), DateUtils.DATE_TIME_PATTERN));

            annexList.add(annexVo);
        }

        //4.获取产品信息
        List<ImportCarryPlanProductInfoRsp> products = carryDetailService.importCarryPlanProductAssociateTransfer(id);
        if (CollectionUtils.isEmpty(products)) {
            return vo;
        }
        for (ImportCarryPlanProductInfoRsp infoRsp : products) {
            //初始化回参实体
            ImportCarryPlanProductVo productVo = new ImportCarryPlanProductVo();
            //赋值
            BeanUtils.copyProperties(infoRsp, productVo);
            //设置出运明细回显主表信息数据
            productVo.setCarryPlanInfo(planInfoVo);
            //设置出运计划费用信息
            productVo.setCostList(costList);
            //设置对应附件信息
            productVo.setAnnexList(annexList);

            //单价
            BigDecimal fcUnitPrice = new BigDecimal("0");
            if(StringUtil.isNotEmpty(infoRsp.getFcUnitPrice())){
                fcUnitPrice = infoRsp.getFcUnitPrice();
            }
            //可申请数量
            BigDecimal canApplyQuantity = new BigDecimal("0");
            if(StringUtil.isNotEmpty(infoRsp.getCanApplyQuantity())){
                canApplyQuantity = infoRsp.getCanApplyQuantity();
            }
            //出运计划中产品数量
            BigDecimal productNum = new BigDecimal("0");
            if(StringUtil.isNotEmpty(infoRsp.getProductNum())){
                productNum = infoRsp.getProductNum();
            }
            //获取出运明细已做数量
            CarryDetailProductEntity detailReq = new CarryDetailProductEntity();
            detailReq.setLotNo(infoRsp.getLotNo());
            detailReq.setProductCode(infoRsp.getProductCode());
            detailReq.setSpecNo(infoRsp.getSpecNo());
            detailReq.setSaleContractNo(infoRsp.getSaleContractNo());
            BigDecimal usedProductSum = carryDetailService.getUsedProductSum(detailReq);

            canApplyQuantity = canApplyQuantity.subtract(usedProductSum);
            if (canApplyQuantity.compareTo(BigDecimal.ZERO) < 1) {
                continue;
            }
            //剩余数量(取可申请数量 与 出运计划中产品数量 这两者最小的数量)
            BigDecimal lastAmount = new BigDecimal("0");
            if(canApplyQuantity.compareTo(productNum) < 1){
                //可申请数量 小于等于 出运计划中产品数量
                lastAmount = canApplyQuantity;
            }else {
                lastAmount = productNum;
            }
            //设置剩余数量(默认等于调拨申请申请数量)
            productVo.setRemainingQuantity(lastAmount);
            //产品数据(默认等于调拨申请申请数量)
            productVo.setProductNum(lastAmount);
            //金额小计 = 单价*数量
            BigDecimal moneySubtotal = fcUnitPrice.multiply(lastAmount);
            productVo.setMoneySubtotal(moneySubtotal);
            //获取对应配件信息
            List<ImportCarryPlanPartsRsp> planParts = carryDetailService.getCarryPlanPartsInfo(id, infoRsp.getProductId());
            //初始化配件回参对象
            List<ImportCarryPlanPartsVo> partsList = new ArrayList<>();
            if (!CollectionUtils.isEmpty(planParts)) {
                for (ImportCarryPlanPartsRsp planPartsRsp : planParts) {
                    ImportCarryPlanPartsVo partsVo = new ImportCarryPlanPartsVo();
                    //赋值
                    BeanUtils.copyProperties(planPartsRsp, partsVo);
                    //配件数量默认等于产品数量
                    partsVo.setPartsAmount(lastAmount);

                    partsList.add(partsVo);
                }
            }
            productVo.setPartsList(partsList);

            vo.add(productVo);
        }
        return vo;
    }

    /**
     * 统计指定出运单号、销售合同号、产品编码、规格编码在出运明细中的数量
     *
     * @param req 查询参数
     * @return 指定出运单号、销售合同号、产品编码、规格编码在出运明细中的数量
     */
    private BigDecimal getRemainingQuantity(ImportPlanRemainingQuantityReq req) {
        //调用接口查询
        List<CarryDetailProductEntity> quantityList = carryDetailProductService.getUsedProductInfo(req);
        //总数量
        BigDecimal sum = new BigDecimal("0");
        for (CarryDetailProductEntity quantity : quantityList) {
            if (StringUtil.isNotEmpty(quantity.getProductNum())) {
                sum = sum.add(quantity.getProductNum());
            }
        }
        return sum;
    }

    /**
     * 新增、修改
     *
     * @param req      新增、修改入参
     * @param creator  创建人
     * @param createNo 创建人编码
     * @return 新增、修改结果
     */
    @Transactional(rollbackFor = Exception.class)
    public R add(AddCarryDetailReq req, String creator, String createNo) throws ParseException {
        //一：单号唯一性校验
        boolean billNoCheckFlag = (null != req.getId() && req.getBillNo().equals(req.getNewBillNo()));
        if (!billNoCheckFlag) {
            //单号做唯一校验
            boolean billNoFlag = checkRepeatBillNo(req.getBillNo());
            if (!billNoFlag) {
                return R.buildError(ResultStatusEnum.BILL_NO_REPEAT);
            }
        }

        //二：主表新增
        Integer id = insert(req, creator, createNo);
        if (id == null) {
            return R.buildError(ResultStatusEnum.SYSTEM_ERROR);
        }

        //三：明细新增及对应配件
        insertDetail(req, id, creator, createNo);

        //四：费用新增
        addCost(req, id, creator, createNo);

        //五：添加附件信息
        boolean flag = addAnnex(req, id, creator, createNo);
        if (!flag) {
            LOGGER.info("出口业务-外销-批量新增附件异常");
            return R.buildError(ResultStatusEnum.SYSTEM_ERROR);
        }
        //删除临时附件信息
        deleteTempAnnex(req.getAnnexList());
        return R.build(ResultStatusEnum.SUCCESS);
    }

    /**
     * 批量处理临时附件信息，将临时附件设置为失效
     *
     * @param annexReqs
     */
    private void deleteTempAnnex(List<AnnexReq> annexReqs) {
        //没有附件
        if (CollectionUtils.isEmpty(annexReqs)) {
            return;
        }
        //存在附件
        for (AnnexReq annex : annexReqs) {
            if (null != annex.getNews()) {
                //旧附件,不用修改
                continue;
            }
            TempAnnexEntity tempAnnex = new TempAnnexEntity();
            //设置临时附件id
            tempAnnex.setId(annex.getId());
            //设置修改时间
            tempAnnex.setUpdateTime(new Date());
            //将附件设置为失效
            tempAnnex.setValid(DataIsValidEnum.INVALID.getId());
            tempAnnexService.update(tempAnnex);
        }

    }

    /**
     * 附件新增
     *
     * @param req  入参信息
     * @param id         主表id
     * @param operator   操作人
     * @param operatorNo 操作人编码
     * @return 是否新增成功(true : 成功 false : 失败)
     */
    private boolean addAnnex(AddCarryDetailReq req, Integer id, String operator, String operatorNo) {
        try {

            List<AnnexReq> annexReqs = req.getAnnexList();
            //没有附件,将该id关联的所有附件设为无效
            if (CollectionUtils.isEmpty(annexReqs)) {
                AnnexEntity annexReq = new AnnexEntity();
                annexReq.setParentId(id);
                annexReq.setModuleId(ModuleTypeEnum.BUSINESS_CARRY_DETAIL.getId());
                List<AnnexEntity> annexList = annexService.queryAll(annexReq);
                if (!CollectionUtils.isEmpty(annexList)) {
                    for (AnnexEntity annex : annexList) {
                        AnnexEntity updateAnnex = new AnnexEntity();
                        updateAnnex.setId(annex.getId());
                        //将被删除的附件设为失效
                        updateAnnex.setValid(DataIsValidEnum.INVALID.getId());
                        annexService.update(updateAnnex);
                    }
                }
                return true;
            }
            //存在附件,新增附件信息
            List<AnnexEntity> list = new ArrayList<>();
            for (AnnexReq annexReq : annexReqs) {
                if (null != annexReq.getNews()) {
                    //属于旧附件 不新增
                    continue;
                }
                AnnexEntity annex = new AnnexEntity();
                BeanUtils.copyProperties(annexReq, annex);
                //设置关联模块id
                annex.setModuleId(ModuleTypeEnum.BUSINESS_CARRY_DETAIL.getId());
                //设置关联模块父id
                annex.setParentId(id);
                //设置上传时间
                annex.setUploadTime(DateUtils.convertStringToDate(annexReq.getUploadTime(), DateUtils.DATE_PATTERN));
                //设置修改时间
                annex.setUpdateTime(new Date());
                //设置操作人
                annex.setOperator(operator);
                //设置操作人编码
                annex.setOperatorNo(operatorNo);
                //设置数据有效
                annex.setValid(1);

                list.add(annex);

                //新增附件日志信息
                DataInfoLogEntity dataInfoLog = new DataInfoLogEntity();
                //模块主表id
                dataInfoLog.setParentId(id);
                //模块id
                dataInfoLog.setModuleId(ModuleTypeEnum.BUSINESS_CARRY_DETAIL.getId());
                //操作人编码
                dataInfoLog.setOperationCode(operatorNo);
                //操作人名称
                dataInfoLog.setOperationName(operator);
                //操作类型
                dataInfoLog.setOperationType(OperationTypeEnum.INSERT_DATA.getId());
                //操作时间
                dataInfoLog.setOperationTime(new Date());
                //操作内容
                dataInfoLog.setOperationContent("附件名称:" + annex.getFileName());

                dataInfoLogService.insert(dataInfoLog);
            }
            if (!CollectionUtils.isEmpty(list)) {
                //附件批量新增
                annexService.batchInsert(list);
            }
            //获取删除的附件
            List<Integer> deleteAnnexIds = req.getDeleteAnnexIds();
            if(deleteAnnexIds.size() > 0){
                //存在被删除的旧附件，数据库删除
                for(Integer deleteAnnexId : deleteAnnexIds){
                    AnnexEntity annexEntity = new AnnexEntity();
                    //附件主键ID
                    annexEntity.setId(deleteAnnexId);
                    //将被删除的附件设为失效
                    annexEntity.setValid(DataIsValidEnum.INVALID.getId());
                    //删除时间
                    annexEntity.setUpdateTime(new Date());

                    annexService.update(annexEntity);
                }
            }
            return true;
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }

    /**
     * 费用新增
     *
     * @param req 新增参数
     * @param id  主表id
     */
    private void addCost(AddCarryDetailReq req, Integer id, String creator, String createNo) {
        if (CollectionUtils.isEmpty(req.getCostList())) {
            return;
        }
        List<CarryDetailCostEntity> addCostList = new ArrayList<>();
        //费用id
        List<Integer> newIds = new ArrayList<>();
        for (AddCarryDetailCostReq cost : req.getCostList()) {
            CarryDetailCostEntity updateReq = new CarryDetailCostEntity();
            //赋值
            BeanUtils.copyProperties(cost, updateReq);

            if (null == cost.getId()) {
                //新增

                //新增日志信息
                DataInfoLogEntity dataInfoLog = new DataInfoLogEntity();
                //模块主表id
                dataInfoLog.setParentId(id);
                //模块id
                dataInfoLog.setModuleId(ModuleTypeEnum.BUSINESS_CARRY_DETAIL.getId());
                //操作人编码
                dataInfoLog.setOperationCode(createNo);
                //操作人名称
                dataInfoLog.setOperationName(creator);
                //操作时间
                dataInfoLog.setOperationTime(new Date());
                //操作类型
                dataInfoLog.setOperationType(OperationTypeEnum.INSERT_DATA.getId());
                //操作内容
                dataInfoLog.setOperationContent("费用信息:");

                dataInfoLogService.insert(dataInfoLog);

                //父id
                updateReq.setParentId(id);
                //创建时间
                updateReq.setCreateDate(new Date());
                //设为有效
                updateReq.setValid(DataIsValidEnum.VALID.getId());

                addCostList.add(updateReq);
            } else {
                //修改

                CarryDetailCostEntity costData = carryDetailCostService.queryById(cost.getId());
                BeanChangeLogUtil logUtil = new BeanChangeLogUtil();
                String info = logUtil.contrastObj(costData, updateReq);
                if(StringUtils.isNotEmpty(info)){
                    //新增日志信息
                    DataInfoLogEntity dataInfoLog = new DataInfoLogEntity();
                    //模块主表id
                    dataInfoLog.setParentId(id);
                    //模块id
                    dataInfoLog.setModuleId(ModuleTypeEnum.BUSINESS_CARRY_DETAIL.getId());
                    //操作人编码
                    dataInfoLog.setOperationCode(createNo);
                    //操作人名称
                    dataInfoLog.setOperationName(creator);
                    //操作时间
                    dataInfoLog.setOperationTime(new Date());
                    //操作类型
                    //操作内容
                    dataInfoLog.setOperationContent("费用信息:" + info);
                    //操作类型
                    dataInfoLog.setOperationType(OperationTypeEnum.UPDATE_DATA.getId());

                    dataInfoLogService.insert(dataInfoLog);
                }

                //修改时间
                updateReq.setModifyTime(new Date());
                carryDetailCostService.update(updateReq);
                newIds.add(updateReq.getId());
            }
        }
        //处理被删除的费用
        handleBeenDeletedCost(id, newIds);

        if (!CollectionUtils.isEmpty(addCostList)) {
            //费用批量新增
            carryDetailCostService.addList(addCostList);
        }
    }

    /**
     * 处理被删除的费用
     *
     * @param id     id
     * @param newIds 费用id
     */
    private void handleBeenDeletedCost(int id, List<Integer> newIds) {
        //修改-找出被删除的费用

        CarryDetailCostEntity costReq = new CarryDetailCostEntity();
        //设置id
        costReq.setParentId(id);
        //查询有效数据
        costReq.setValid(DataIsValidEnum.VALID.getId());
        //调用接口查询结果
        List<CarryDetailCostEntity> costList = carryDetailCostService.queryAll(costReq);
        if (!CollectionUtils.isEmpty(costList)) {
            //获取id集合
            List<Integer> oldIds = costList.stream().map(p -> p.getId()).collect(Collectors.toList());
            //找出被删除的id
            Collection collection = new ArrayList(oldIds);
            collection.removeAll(newIds);
            if (collection.size() > 0) {
                //遍历被删除的费用
                Iterator<Integer> ids = collection.iterator();
                while (ids.hasNext()) {
                    int costId = ids.next();
                    CarryDetailCostEntity updateReq = new CarryDetailCostEntity();
                    //修改主键
                    updateReq.setId(costId);
                    //修改时间
                    updateReq.setModifyTime(new Date());
                    //设为无效
                    updateReq.setValid(DataIsValidEnum.INVALID.getId());

                    carryDetailCostService.update(updateReq);
                }
            }
        }
    }

    /**
     * 明细新增
     *
     * @param req 新增对象
     * @param id  主表id
     */
    public void insertDetail(AddCarryDetailReq req, int id, String creator, String createNo) {
        if (!CollectionUtils.isEmpty(req.getDetailList())) {
            //获取明细id集合
            List<Integer> newIds = new ArrayList<>();
            for (AddCarryDetailProductReq detailReq : req.getDetailList()) {
                //初始化明细对象
                CarryDetailProductEntity detail = new CarryDetailProductEntity();
                //赋值
                BeanUtils.copyProperties(detailReq, detail);
                //设置主表id
                detail.setCarryDetailId(id);
                //设置数据有效性(0:无效 1:有效)
                detail.setValid(DataIsValidEnum.VALID.getId());
                if (null == detailReq.getId()) {
                    //新增日志信息
                    DataInfoLogEntity dataInfoLog = new DataInfoLogEntity();
                    //模块主表id
                    dataInfoLog.setParentId(id);
                    //模块id
                    dataInfoLog.setModuleId(ModuleTypeEnum.BUSINESS_CARRY_DETAIL.getId());
                    //操作人编码
                    dataInfoLog.setOperationCode(createNo);
                    //操作人名称
                    dataInfoLog.setOperationName(creator);
                    //操作类型
                    dataInfoLog.setOperationType(OperationTypeEnum.INSERT_DATA.getId());
                    //操作时间
                    dataInfoLog.setOperationTime(new Date());
                    //操作内容
                    dataInfoLog.setOperationContent("产品信息:" + "产品编码:" + detail.getProductCode() + ",规格编码:" + detail.getSpecNo());

                    dataInfoLogService.insert(dataInfoLog);

                    //新增
                    carryDetailProductService.insert(detail);
                    //获取明细id
                    Integer detailId = detail.getId();
                    newIds.add(detailId);
                    //配件新增
                    if (!CollectionUtils.isEmpty(detailReq.getPartsList())) {
                        //初始化配件对象集合
                        List<CarryDetailProductPartsEntity> partsList = new ArrayList<>();
                        for (AddCarryDetailProductPartsReq parts : detailReq.getPartsList()) {
                            //初始化配件对象
                            CarryDetailProductPartsEntity partsEntity = new CarryDetailProductPartsEntity();
                            //赋值
                            BeanUtils.copyProperties(parts, partsEntity);
                            //主键id
                            partsEntity.setCarryDetailId(id);
                            //产品明细id
                            partsEntity.setProductDetailId(detailId);
                            //设置数据有效性(0:无效 1:有效)
                            partsEntity.setValid(DataIsValidEnum.VALID.getId());

                            partsList.add(partsEntity);
                        }
                        if (!CollectionUtils.isEmpty(partsList)) {
                            //新增配件
                            carryDetailProductPartsService.addList(partsList);
                        }

                    }
                } else {
                    //修改

                    //添加修改日志
                    //获取修改前对象数据
                    CarryDetailProductEntity oldData = carryDetailProductService.queryById(detailReq.getId());
                    BeanChangeLogUtil logUtil = new BeanChangeLogUtil();
                    String info = logUtil.contrastObj(oldData, detail);
                    if(StringUtils.isNotEmpty(info)){
                        //新增日志信息
                        DataInfoLogEntity dataInfoLog = new DataInfoLogEntity();
                        //模块主表id
                        dataInfoLog.setParentId(id);
                        //模块id
                        dataInfoLog.setModuleId(ModuleTypeEnum.BUSINESS_CARRY_DETAIL.getId());
                        //操作人编码
                        dataInfoLog.setOperationCode(createNo);
                        //操作人名称
                        dataInfoLog.setOperationName(creator);
                        //操作类型
                        dataInfoLog.setOperationType(OperationTypeEnum.UPDATE_DATA.getId());
                        //操作时间
                        dataInfoLog.setOperationTime(new Date());
                        //操作内容
                        dataInfoLog.setOperationContent("产品信息:" + info);

                        dataInfoLogService.insert(dataInfoLog);
                    }

                    //获取明细id
                    newIds.add(detailReq.getId());
                    //明细修改
                    carryDetailProductService.update(detail);
                    //配件修改
                    if (!CollectionUtils.isEmpty(detailReq.getPartsList())) {
                        List<Integer> newPartsIds = new ArrayList<>();
                        for (AddCarryDetailProductPartsReq parts : detailReq.getPartsList()) {
                            if (null == parts.getId()) {
                                //新增
                                //初始化配件对象
                                CarryDetailProductPartsEntity partsEntity = new CarryDetailProductPartsEntity();
                                //赋值
                                BeanUtils.copyProperties(parts, partsEntity);
                                //报价id
                                partsEntity.setCarryDetailId(id);
                                //产品明细id
                                partsEntity.setProductDetailId(detailReq.getId());
                                //设置数据有效性(0:无效 1:有效)
                                partsEntity.setValid(DataIsValidEnum.VALID.getId());

                                carryDetailProductPartsService.insert(partsEntity);
                                //获取配件id
                                newPartsIds.add(partsEntity.getId());
                            } else {
                                //修改
                                if (detailReq.getId().equals(parts.getProductDetailId())) {
                                    //获取配件id
                                    newPartsIds.add(parts.getId());
                                    //初始化配件对象
                                    CarryDetailProductPartsEntity partsEntity = new CarryDetailProductPartsEntity();
                                    //赋值
                                    BeanUtils.copyProperties(parts, partsEntity);

                                    carryDetailProductPartsService.update(partsEntity);
                                }
                            }

                        }
                        //处理被删除的配件
                        handleBeenDeletedParts(detailReq.getId(), newPartsIds);
                    }
                }

            }

            //处理被删除的明细
            handleBeenDeletedDetail(req, id, newIds, creator, createNo);

        }
    }

    /**
     * 处理被删除的明细
     *
     * @param req    明细
     * @param id     主表id
     * @param newIds 修改后未被删除的细id集合
     */
    private void handleBeenDeletedDetail(AddCarryDetailReq req, int id, List<Integer> newIds, String creator, String createNo) {
        if (null != req.getId()) {
            //修改-找出被删除的明细

            CarryDetailProductEntity detailReq = new CarryDetailProductEntity();
            //设置主表id
            detailReq.setCarryDetailId(id);
            //查询有效数据
            detailReq.setValid(DataIsValidEnum.VALID.getId());
            //调用接口查询结果
            List<CarryDetailProductEntity> detailList = carryDetailProductService.queryAll(detailReq);
            if (!CollectionUtils.isEmpty(detailList)) {
                //获取id集合
                List<Integer> oldIds = detailList.stream().map(p -> p.getId()).collect(Collectors.toList());
                //找出被删除的id
                Collection collection = new ArrayList(oldIds);
                collection.removeAll(newIds);
                if (collection.size() > 0) {
                    //遍历删除被删除的明细
                    Iterator<Integer> ids = collection.iterator();
                    while (ids.hasNext()) {
                        int detailId = ids.next();

                        //添加日志
                        CarryDetailProductEntity detailEntity = carryDetailProductService.queryById(detailId);
                        //新增日志信息
                        DataInfoLogEntity dataInfoLog = new DataInfoLogEntity();
                        //模块主表id
                        dataInfoLog.setParentId(id);
                        //模块id
                        dataInfoLog.setModuleId(ModuleTypeEnum.BUSINESS_CARRY_DETAIL.getId());
                        //操作人编码
                        dataInfoLog.setOperationCode(createNo);
                        //操作人名称
                        dataInfoLog.setOperationName(creator);
                        //操作类型
                        dataInfoLog.setOperationType(OperationTypeEnum.DELETE_DATA.getId());
                        //操作时间
                        dataInfoLog.setOperationTime(new Date());
                        //操作内容
                        dataInfoLog.setOperationContent("产品信息:" + "产品编码:" + detailEntity.getProductCode() + ",规格编码:" + detailEntity.getSpecNo());

                        dataInfoLogService.insert(dataInfoLog);

                        CarryDetailProductEntity detail = new CarryDetailProductEntity();
                        detail.setId(detailId);
                        detail.setValid(DataIsValidEnum.INVALID.getId());
                        //将删除的明细设为无效
                        carryDetailProductService.update(detail);

                        //获取对应的配件数据
                        CarryDetailProductPartsEntity query = new CarryDetailProductPartsEntity();
                        //主键id
                        query.setCarryDetailId(id);
                        //产品明细id
                        query.setProductDetailId(detailId);
                        //有效的数据
                        query.setValid(DataIsValidEnum.VALID.getId());
                        //调用接口查询
                        List<CarryDetailProductPartsEntity> partsList = carryDetailProductPartsService.queryAll(query);
                        if (!CollectionUtils.isEmpty(partsList)) {
                            for (CarryDetailProductPartsEntity partsEntity : partsList) {
                                CarryDetailProductPartsEntity updateReq = new CarryDetailProductPartsEntity();
                                //修改主键
                                updateReq.setId(partsEntity.getId());
                                //设为无效
                                updateReq.setValid(DataIsValidEnum.INVALID.getId());

                                carryDetailProductPartsService.update(updateReq);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 处理被删除的配件
     *
     * @param id     产品明细id
     * @param newIds 配件id
     */
    private void handleBeenDeletedParts(int id, List<Integer> newIds) {
        CarryDetailProductPartsEntity partsReq = new CarryDetailProductPartsEntity();
        //设置产品明细id
        partsReq.setProductDetailId(id);
        //查询有效数据
        partsReq.setValid(DataIsValidEnum.VALID.getId());
        //调用接口查询结果
        List<CarryDetailProductPartsEntity> partsList = carryDetailProductPartsService.queryAll(partsReq);
        if (!CollectionUtils.isEmpty(partsList)) {
            //获取id集合
            List<Integer> oldIds = partsList.stream().map(p -> p.getId()).collect(Collectors.toList());
            //找出被删除的id
            Collection collection = new ArrayList(oldIds);
            collection.removeAll(newIds);
            if (collection.size() > 0) {
                //遍历删除被删除的明细
                Iterator<Integer> ids = collection.iterator();
                while (ids.hasNext()) {
                    int partsId = ids.next();
                    CarryDetailProductPartsEntity updateReq = new CarryDetailProductPartsEntity();
                    //修改主键
                    updateReq.setId(partsId);
                    //设为无效
                    updateReq.setValid(DataIsValidEnum.INVALID.getId());

                    carryDetailProductPartsService.update(updateReq);

                }
            }
        }
    }

    /**
     * 新增主表信息
     *
     * @param req      新增参数
     * @param creator  创建人
     * @param createNo 创建人编码
     * @return 主表id
     * @throws ParseException
     */
    private Integer insert(AddCarryDetailReq req, String creator, String createNo) throws ParseException {
        //初始化对象
        CarryDetailEntity contract = new CarryDetailEntity();
        //赋值
        BeanUtils.copyProperties(req, contract);
        //出运日期
        contract.setTime(DateUtils.convertStringToDate(req.getTime(), DateUtils.DATE_PATTERN));
        //货号日期
        contract.setArticleNumberDate(DateUtils.convertStringToDate(req.getArticleNumberDate(), DateUtils.DATE_PATTERN));
        //预计开船日期
        contract.setActualTimeDismissal(DateUtils.convertStringToDate(req.getActualTimeDismissal(), DateUtils.DATE_PATTERN));
        //预计到达日期ETA
        contract.setEstimatedArrivalDate(DateUtils.convertStringToDate(req.getEstimatedArrivalDate(), DateUtils.DATE_PATTERN));
        //进仓装柜日期
        contract.setLoadingTime(DateUtils.convertStringToDate(req.getLoadingTime(), DateUtils.DATE_PATTERN));

        if (null == req.getId()) {
            //新增

            //保存后进草稿箱
            contract.setStatus(OperationStatusEnum.DRAFT_BOX.getId());
            //设置数据有效性(0:无效 1:有效)
            contract.setValid(DataIsValidEnum.VALID.getId());
            //设置创建时间
            contract.setCreateDate(new Date());
            //设置创建人
            contract.setOperator(creator);
            //设置创建人编码
            contract.setOperationCode(createNo);
            //调用接口新增调拨
            int result = carryDetailService.insert(contract);
            if(1 == result){
                //新增添加日志
                BeanChangeLogUtil logUtil = new BeanChangeLogUtil();
                String info = logUtil.contrastObj(new CarryDetailEntity(), contract);
                if(StringUtils.isNotEmpty(info)) {
                    //新增日志信息
                    DataInfoLogEntity dataInfoLog = new DataInfoLogEntity();
                    //模块主表id
                    dataInfoLog.setParentId(contract.getId());
                    //模块id
                    dataInfoLog.setModuleId(ModuleTypeEnum.BUSINESS_CARRY_DETAIL.getId());
                    //操作人编码
                    dataInfoLog.setOperationCode(createNo);
                    //操作人名称
                    dataInfoLog.setOperationName(creator);
                    //操作类型
                    dataInfoLog.setOperationType(OperationTypeEnum.INSERT_DATA.getId());
                    //操作时间
                    dataInfoLog.setOperationTime(new Date());
                    //操作内容
                    dataInfoLog.setOperationContent("主信息:" + info);

                    dataInfoLogService.insert(dataInfoLog);
                }
            }
            return 1 == result ? contract.getId() : null;
        } else {
            //修改

            //如果明细、费用为空，则删除对应所有明细和费用
            if (CollectionUtils.isEmpty(req.getDetailList())) {
                CarryDetailProductEntity detailReq = new CarryDetailProductEntity();
                //设置报价id
                detailReq.setCarryDetailId(req.getId());
                //数据有效
                detailReq.setValid(DataIsValidEnum.VALID.getId());
                List<CarryDetailProductEntity> detailList = carryDetailProductService.queryAll(detailReq);
                if (!CollectionUtils.isEmpty(detailList)) {
                    for (CarryDetailProductEntity detail : detailList) {
                        CarryDetailProductEntity updateReq = new CarryDetailProductEntity();
                        //主键id
                        updateReq.setId(detail.getId());
                        //设为无效
                        updateReq.setValid(DataIsValidEnum.INVALID.getId());

                        carryDetailProductService.update(updateReq);
                    }
                }
            }

            if (CollectionUtils.isEmpty(req.getCostList())) {
                CarryDetailCostEntity costReq = new CarryDetailCostEntity();
                //设置id
                costReq.setParentId(req.getId());
                //数据有效
                costReq.setValid(DataIsValidEnum.VALID.getId());
                List<CarryDetailCostEntity> costList = carryDetailCostService.queryAll(costReq);
                if (!CollectionUtils.isEmpty(costList)) {
                    for (CarryDetailCostEntity cost : costList) {
                        CarryDetailCostEntity updateReq = new CarryDetailCostEntity();
                        //主键id
                        updateReq.setId(cost.getId());
                        //修改时间
                        updateReq.setModifyTime(new Date());
                        //设为无效
                        updateReq.setValid(DataIsValidEnum.INVALID.getId());

                        carryDetailCostService.update(updateReq);
                    }
                }
            }
            //设置修改时间
            contract.setModifyTime(new Date());

            //添加修改日志
            //获取修改前对象数据
            CarryDetailEntity oldData = carryDetailService.queryById(req.getId());
            BeanChangeLogUtil logUtil = new BeanChangeLogUtil();
            String info = logUtil.contrastObj(oldData, contract);
            if(StringUtils.isNotEmpty(info)) {
                //新增日志信息
                DataInfoLogEntity dataInfoLog = new DataInfoLogEntity();
                //模块主表id
                dataInfoLog.setParentId(req.getId());
                //模块id
                dataInfoLog.setModuleId(ModuleTypeEnum.BUSINESS_CARRY_DETAIL.getId());
                //操作人编码
                dataInfoLog.setOperationCode(createNo);
                //操作人名称
                dataInfoLog.setOperationName(creator);
                //操作类型
                dataInfoLog.setOperationType(OperationTypeEnum.UPDATE_DATA.getId());
                //操作时间
                dataInfoLog.setOperationTime(new Date());
                //操作内容
                dataInfoLog.setOperationContent("主信息:" + info);

                dataInfoLogService.insert(dataInfoLog);
            }

            //获取修改前,单据状态
            CarryDetailEntity carryDetailEntity = carryDetailService.queryById(req.getId());
            if(carryDetailEntity.getStatus() == OperationStatusEnum.APPROVED_BOX.getId()){
                //审批通过后，点击修改保存提交后，单据不要改变所在箱体
                contract.setStatus(OperationStatusEnum.APPROVED_BOX.getId());
            }else {
                //未通过数据,修改后单据为草稿箱
                contract.setStatus(OperationStatusEnum.DRAFT_BOX.getId());
            }
            return carryDetailService.update(contract) == 1 ? contract.getId() : null;
        }

    }

    /**
     * 校验单号是否存在
     *
     * @param billNo 单号
     * @return true:不重复 false:重复
     */
    private boolean checkRepeatBillNo(String billNo) {
        CarryDetailEntity req = new CarryDetailEntity();
        req.setBillNo(billNo);
        req.setValid(DataIsValidEnum.VALID.getId());
        List<CarryDetailEntity> contractEntities = carryDetailService.queryAll(req);
        if (CollectionUtils.isEmpty(contractEntities)) {
            return true;
        }
        return false;
    }


    /**
     * 详情
     *
     * @param id id
     * @return 详情
     */
    public CarryDetailVo detail(Integer id) {
        //初始化回参对象
        CarryDetailVo vo = new CarryDetailVo();
        if (null == id) {
            return vo;
        }
        //第一步：获取主表信息
        CarryDetailEntity contract = carryDetailService.queryById(id);
        if (null == contract || null == contract.getId()) {
            return vo;
        }
        //赋值
        BeanUtils.copyProperties(contract, vo);
        //出运日期
        vo.setTime(DateUtils.format(contract.getTime(), DateUtils.DATE_PATTERN));
        //货号日期
        vo.setArticleNumberDate(DateUtils.format(contract.getArticleNumberDate(), DateUtils.DATE_PATTERN));
        //预计开船日期
        vo.setActualTimeDismissal(DateUtils.format(contract.getActualTimeDismissal(), DateUtils.DATE_PATTERN));
        //预计到达日期ETA
        vo.setEstimatedArrivalDate(DateUtils.format(contract.getEstimatedArrivalDate(), DateUtils.DATE_PATTERN));
        //进仓装柜日期
        vo.setLoadingTime(DateUtils.format(contract.getLoadingTime(), DateUtils.DATE_PATTERN));
        //制单日期
        vo.setCreateDate(DateUtils.format(contract.getCreateDate(), DateUtils.DATE_PATTERN));

        //第二步：获取产品明细数据
        CarryDetailProductEntity contractDetailReq = new CarryDetailProductEntity();
        //id
        contractDetailReq.setCarryDetailId(id);
        //有效数据
        contractDetailReq.setValid(DataIsValidEnum.VALID.getId());
        //调用接口查询产品明细数据
        List<CarryDetailProductEntity> contractDetailList = carryDetailProductService.queryAll(contractDetailReq);
        if (!CollectionUtils.isEmpty(contractDetailList)) {
            //初始化回参对象集合
            List<CarryDetailProductDetailVo> detailList = new ArrayList<>();
            for (CarryDetailProductEntity detailEntity : contractDetailList) {
                //初始化回参对象
                CarryDetailProductDetailVo productDetailVo = new CarryDetailProductDetailVo();
                //赋值
                BeanUtils.copyProperties(detailEntity, productDetailVo);
                //校验该产品在下游是否被调用 true:未被调用 false:已被调用
                /*BigDecimal sum = getUsedQuantity(contract.getBillNo(), detailEntity.getProductCode(), detailEntity.getSpecificationCode());
                if(sum.compareTo(BigDecimal.ZERO) == 1){
                    //已被调用，不能删除
                    productDetailVo.setIsDelete(1);
                    //设置已被调用数量
                    productDetailVo.setUsedQuantity(sum);
                }else {
                    //未被调用，可删除
                    productDetailVo.setIsDelete(0);
                }*/
                //获取对应配件信息
                CarryDetailProductPartsEntity partsReq = new CarryDetailProductPartsEntity();
                //设置id
                partsReq.setCarryDetailId(id);
                //设置产品明细id
                partsReq.setProductDetailId(detailEntity.getId());
                //设置数据有效性
                partsReq.setValid(DataIsValidEnum.VALID.getId());
                //查询结果
                List<CarryDetailProductPartsEntity> partsEntityList = carryDetailProductPartsService.queryAll(partsReq);
                if (!CollectionUtils.isEmpty(partsEntityList)) {
                    List<CarryDetailProductPartsDetailVo> partsList = partsEntityList.stream().map(p -> {
                        CarryDetailProductPartsDetailVo partsVo = new CarryDetailProductPartsDetailVo();
                        //赋值
                        BeanUtils.copyProperties(p, partsVo);
                        return partsVo;
                    }).collect(Collectors.toList());

                    //添加相关配件集合
                    productDetailVo.setPartsList(partsList);
                }

                detailList.add(productDetailVo);
            }
            //添加产品明细数据
            vo.setDetailList(detailList);
        }

        //第三步：获取费用数据
        CarryDetailCostEntity costReq = new CarryDetailCostEntity();
        //设置id
        costReq.setParentId(id);
        //获取有效数据
        costReq.setValid(DataIsValidEnum.VALID.getId());
        //查询结果
        List<CarryDetailCostEntity> costEntities = carryDetailCostService.queryAll(costReq);
        if (!CollectionUtils.isEmpty(costEntities)) {
            List<CarryDetailCostDetailVo> costList = costEntities.stream().map(p -> {
                CarryDetailCostDetailVo costVo = new CarryDetailCostDetailVo();
                //赋值
                BeanUtils.copyProperties(p, costVo);
                return costVo;
            }).collect(Collectors.toList());

            //添加相关费用信息
            vo.setCostList(costList);
        }

        //第四步：获取对应附件信息
        AnnexEntity annex = new AnnexEntity();
        //设置模块id
        annex.setModuleId(ModuleTypeEnum.BUSINESS_CARRY_DETAIL.getId());
        //设置父id
        annex.setParentId(id);
        //设置数据有效
        annex.setValid(DataIsValidEnum.VALID.getId());
        //调用接口查询附件信息
        List<AnnexEntity> annexList = annexService.queryAll(annex);
        if (!CollectionUtils.isEmpty(annexList)) {
            List<AnnexVo> annexVos = annexList.stream().map(p -> {
                AnnexVo annexVo = new AnnexVo();
                //赋值
                BeanUtils.copyProperties(p, annexVo);
                //上传时间转换
                annexVo.setUploadTime(DateUtils.format(p.getUploadTime(), DateUtils.DATE_TIME_PATTERN));
                //设置附件为旧附件,用以区分修改时附件状态
                annexVo.setNews(0);

                return annexVo;
            }).collect(Collectors.toList());

            vo.setAnnexList(annexVos);
        }

        //第五步：获取对应日志信息
        DataInfoLogEntity logReq = new DataInfoLogEntity();
        //主表id
        logReq.setParentId(id);
        //模块id
        logReq.setModuleId(ModuleTypeEnum.BUSINESS_CARRY_DETAIL.getId());
        //查询结果
        List<DataInfoLogEntity> dataInfoLog = dataInfoLogService.queryAll(logReq);
        if(!CollectionUtils.isEmpty(dataInfoLog)){
            List<DataInfoLogVo> logVos = new ArrayList<>();
            for(DataInfoLogEntity log : dataInfoLog){
                DataInfoLogVo logVo = new DataInfoLogVo();
                //赋值
                BeanUtils.copyProperties(log, logVo);
                //日期处理
                logVo.setOperationTime(DateUtils.format(log.getOperationTime(), DateUtils.DATE_TIME_PATTERN));
                //操作类型
                logVo.setOperationType(OperationTypeEnum.getDescById(log.getOperationType()));

                logVos.add(logVo);
            }

            vo.setLogList(logVos);
        }

        return vo;
    }

    /**
     * 获取本月出运单据
     *
     * @param name 操作员
     * @param code 操作员编码
     * @return 本月出运单据
     */
    public long getCarryBillNoCount(String name, String code) {
        //初始化查询对象
        StatisticsInfoReq infoReq = new StatisticsInfoReq();
        infoReq.setOperator(name);
        infoReq.setOperationCode(code);
        infoReq.setCreateDateStart(DateUtils.format(DateUtils.getStartTimeOfTheMonth(), DateUtils.DATE_PATTERN));
        infoReq.setCreateDateEnd(DateUtils.format(DateUtils.getEndTimeOfTheMonth(), DateUtils.DATE_PATTERN));
        //查询结果
        return carryDetailService.getCarryBillNoCount(infoReq);
    }

    /**
     * 获取本月外销、出货统计
     *
     * @return 本月外销、出货统计
     */
    public Object statisticsChartInfo() {
        JSONObject obj = new JSONObject();
        //获取外销数据
        Map<String, BigDecimal> exportMap = getExportInfoMap();
        //获取出运明细信息
        Map<String, BigDecimal> detailMap = getCarryDetailMap();
        //获取外销、出货业务员
        List<String> salesmanList = getAllSalesmanName(exportMap, detailMap);
        //数据组装
        //业务员
        JSONArray yAxisData = new JSONArray();
        //外销数据
        JSONArray exportData = new JSONArray();
        //出货数据
        JSONArray detailData = new JSONArray();
        for (String salesman : salesmanList) {
            BigDecimal exportNum = new BigDecimal("0");
            for (Map.Entry<String, BigDecimal> exportInfo : exportMap.entrySet()) {
                String exportSalesman = exportInfo.getKey();
                BigDecimal num = exportInfo.getValue();
                if (salesman.equals(exportSalesman)) {
                    exportNum = num;
                    break;
                }
            }
            exportData.add(exportNum.doubleValue());

            BigDecimal detailNum = new BigDecimal("0");
            for (Map.Entry<String, BigDecimal> detailInfo : detailMap.entrySet()) {

                String detailSalesman = detailInfo.getKey();
                BigDecimal num = detailInfo.getValue();
                if (salesman.equals(detailSalesman)) {
                    detailNum = num;
                    break;
                }
            }
            detailData.add(detailNum.doubleValue());

            yAxisData.add(salesman);
        }

        obj.put("yAxisData", yAxisData);
        obj.put("exportData", exportData);
        obj.put("detailData", detailData);
        return obj;
    }

    /**
     * 获取外销、出货业务员
     *
     * @param exportMap 外销信息
     * @param detailMap 出货信息
     * @return 外销、出货业务员
     */
    private List<String> getAllSalesmanName(Map<String, BigDecimal> exportMap, Map<String, BigDecimal> detailMap) {
        List<String> salesmanList = new ArrayList<>();
        for (Map.Entry<String, BigDecimal> exportInfo : exportMap.entrySet()) {
            String exportSalesman = exportInfo.getKey();
            if (salesmanList.contains(exportSalesman)) {
                continue;
            }
            salesmanList.add(exportSalesman);
        }
        for (Map.Entry<String, BigDecimal> detailInfo : detailMap.entrySet()) {
            String detailSalesman = detailInfo.getKey();
            if (salesmanList.contains(detailSalesman)) {
                continue;
            }
            salesmanList.add(detailSalesman);
        }

        return salesmanList;
    }

    /**
     * 获取出运明细信息
     *
     * @return 出运明细信息
     */
    private Map<String, BigDecimal> getCarryDetailMap() {
        Map<String, BigDecimal> map = new HashMap<>();
        //初始化查询对象
        StatisticsInfoReq infoReq = new StatisticsInfoReq();
        infoReq.setCreateDateStart(DateUtils.format(DateUtils.getStartTimeOfTheMonth(), DateUtils.DATE_PATTERN));
        infoReq.setCreateDateEnd(DateUtils.format(DateUtils.getEndTimeOfTheMonth(), DateUtils.DATE_PATTERN));
        //查询结果
        List<CarryDetailEntity> carryInfo = carryDetailService.getCarryInfo(infoReq);
        if (CollectionUtils.isEmpty(carryInfo)) {
            return map;
        }
        //业务员集合
        List<String> salesmanCodeList = new ArrayList<>();
        for (CarryDetailEntity contract : carryInfo) {
            //美金汇率
            BigDecimal usdRate = new BigDecimal("0");
            if (StringUtil.isNotEmpty(contract.getUsdRate())) {
                usdRate = contract.getUsdRate();
            }
            //合同总额
            BigDecimal totalContractAmount = new BigDecimal("0");
            if (StringUtil.isNotEmpty(contract.getTotalInvoiceAmount())) {
                totalContractAmount = contract.getTotalInvoiceAmount();
            }
            BigDecimal usdAmount = usdRate.multiply(totalContractAmount);

            //业务员编码
            String salesmanCode = contract.getSalesmanCode();
            //业务员名称
            String salesmanName = contract.getSalesmanName();
            if (StringUtils.isEmpty(salesmanCode) || StringUtils.isEmpty(salesmanName)) {
                continue;
            }
            if (salesmanCodeList.contains(salesmanCode)) {
                //已存在该业务员,金额累加
                BigDecimal amount = map.get(salesmanName);
                amount = amount.add(usdAmount);

                //更新金额
                map.put(salesmanName, amount);
            } else {
                //不存在该业务员,将该业务员加到集合中
                salesmanCodeList.add(salesmanCode);
                //将该业务员数据加入map中
                map.put(salesmanName, usdAmount);
            }
        }
        return map;
    }

    /**
     * 获取外销数据
     *
     * @return 外销数据
     */
    private Map<String, BigDecimal> getExportInfoMap() {
        Map<String, BigDecimal> map = new HashMap<>();
        //初始化查询对象
        StatisticsInfoReq infoReq = new StatisticsInfoReq();
        infoReq.setCreateDateStart(DateUtils.format(DateUtils.getStartTimeOfTheMonth(), DateUtils.DATE_PATTERN));
        infoReq.setCreateDateEnd(DateUtils.format(DateUtils.getEndTimeOfTheMonth(), DateUtils.DATE_PATTERN));
        //查询结果
        List<ExportContractEntity> contractList = exportContractService.getExportInfo(infoReq);
        if (CollectionUtils.isEmpty(contractList)) {
            return map;
        }
        //业务员集合
        List<String> salesmanCodeList = new ArrayList<>();
        for (ExportContractEntity contract : contractList) {
            //美金汇率
            BigDecimal usdRate = new BigDecimal("0");
            if (StringUtil.isNotEmpty(contract.getUsdRate())) {
                usdRate = contract.getUsdRate();
            }
            //合同总额
            BigDecimal totalContractAmount = new BigDecimal("0");
            if (StringUtil.isNotEmpty(contract.getTotalContractAmount())) {
                totalContractAmount = contract.getTotalContractAmount();
            }
            BigDecimal usdAmount = usdRate.multiply(totalContractAmount);

            //业务员编码
            String salesmanCode = contract.getSalesmanCode();
            //业务员名称
            String salesmanName = contract.getSalesmanName();
            if (StringUtils.isEmpty(salesmanCode) || StringUtils.isEmpty(salesmanName)) {
                continue;
            }
            if (salesmanCodeList.contains(salesmanCode)) {
                //已存在该业务员,金额累加
                BigDecimal amount = map.get(salesmanName);
                amount = amount.add(usdAmount);

                //更新金额
                map.put(salesmanName, amount);
            } else {
                //不存在该业务员,将该业务员加到集合中
                salesmanCodeList.add(salesmanCode);
                //将该业务员数据加入map中
                map.put(salesmanName, usdAmount);
            }
        }

        return map;
    }


    /**
     * 统计采购产品情况一览统计--集合
     * @param req
     * @return
     */
    List<StatisticsPurchaseInfoRsp> statisticsPurchaseInfo(PurchaseStatisticsOneReq req){
        List<StatisticsPurchaseInfoRsp> list = carryDetailService.getStatisticsPurchaseInfo(req);
        for (StatisticsPurchaseInfoRsp p:list){
            //是否含税（1:含税出厂价2:未税出厂价3:含税FOB价4:未税FOB价）
            String taxIncluded=p.getTaxIncluded();
            if (StringUtils.isNotEmpty(taxIncluded)){
                switch (taxIncluded){
                    case "1":
                        p.setTaxIncluded("含税出厂价");
                        break;
                    case "2":
                        p.setTaxIncluded("未税出厂价");
                        break;
                    case "3":
                        p.setTaxIncluded("含税FOB价");
                        break;
                    case "4":
                        p.setTaxIncluded("未税FOB价");
                        break;
                    default:
                        p.setTaxIncluded("");
                }

                BigDecimal price= p.getPrice();
                BigDecimal benchmarkPrice=p.getBenchmarkPrice();
                if (p.getBenchmarkPrice()!=null){
                    BigDecimal subtract = benchmarkPrice.subtract(price);
                    p.setDifferentialPrice(subtract);
                    p.setCostDown(subtract.multiply(p.getAmount()));
                }


            }else {
                p.setTaxIncluded(null);
                p.setBenchmarkPrice(null);
                p.setDifferentialPrice(null);
                p.setCostDown(null);
            }

            switch (p.getPurchaseType()){
                case "1":
                    p.setPurchaseType("成品");
                    break;
                case "2":
                    p.setPurchaseType("配件");
                    break;
                case "3":
                    p.setPurchaseType("备货");
                    break;
                case "4":
                    p.setPurchaseType("外销");
                    break;
                case "5":
                    p.setPurchaseType("样品采购");
                    break;
            }
        }
        return list;
    }
    /**
     * 统计采购产品情况一览统计--分页
     *
     * @param req 查询参数
     * @return 采购产品情况一览统计
     */
    public PageInfo<StatisticsPurchaseInfoVo> getPurchaseStatisticsOneByPage(PurchaseStatisticsOneReq req) {
        //获取采购信息
        List<StatisticsPurchaseInfoRsp> statisticsPurchaseInfo = statisticsPurchaseInfo(req);
        //初始化回参对象集合
        List<StatisticsPurchaseInfoVo> voList = new ArrayList<>();
        PageInfo pageInfo = new PageInfo(statisticsPurchaseInfo);
        if (CollectionUtils.isEmpty(statisticsPurchaseInfo)) {
            pageInfo.setList(voList);
            return pageInfo;
        }
        voList = getPurchaseStatisticsData(statisticsPurchaseInfo);

        pageInfo.setList(voList);
        return pageInfo;
    }

    /**
     * 获取采购产品情况一览统计并导出
     * @param req 查询条件
     * @return 获取采购产品情况一览统计并导出
     */
    public JSONObject getPurchaseStatisticsAndExport(PurchaseStatisticsOneReq req){
        //调用接口查询
        List<StatisticsPurchaseInfoRsp> statisticsPurchaseInfo = statisticsPurchaseInfo(req);
        JSONObject obj = new JSONObject();
        //获取excel的title信息
        JSONArray titleList = getTitleInfoOfOneStatistics();
        JSONArray data = new JSONArray();
        data.add(titleList);
        if(CollectionUtils.isEmpty(statisticsPurchaseInfo)){
            obj.put("data", data);
            return obj;
        }
        List<StatisticsPurchaseInfoVo> voList = getPurchaseStatisticsData(statisticsPurchaseInfo);

        //封装数据
        getEncapsulationStatisticsInfo(data, voList);

        obj.put("data", data);
        return obj;
    }

    /**
     * 封装数据
     * @param data 封装后数据
     * @param voList 原始数据
     */
    private void getEncapsulationStatisticsInfo(JSONArray data, List<StatisticsPurchaseInfoVo> voList){
        //产品数量
        BigDecimal amount = new BigDecimal("0");
        //采购金额
        BigDecimal priceSubtotal = new BigDecimal("0");
        //已计划数量
        BigDecimal planAmount = new BigDecimal("0");
        //未计划数量
        BigDecimal unPlanAmount = new BigDecimal("0");
        //出运数量
        BigDecimal productNum = new BigDecimal("0");
        //未出运数量
        BigDecimal unProductNum = new BigDecimal("0");
        for(StatisticsPurchaseInfoVo vo : voList){
            JSONArray infoList = new JSONArray();
            infoList.add(getNotNullOfStringInfo(vo.getPurchaseNo()));
            infoList.add(getNotNullOfStringInfo(vo.getPurchaseType()));
            infoList.add(getNotNullOfStringInfo(vo.getPaymentType()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getEarnestRate()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getEarnestMoney()));
            infoList.add(getNotNullOfStringInfo(vo.getMemo()));
            infoList.add(getNotNullOfStringInfo(vo.getSalesContractNo()));
            infoList.add(getNotNullOfStringInfo(vo.getSupplierName()));
            infoList.add(getNotNullOfStringInfo(vo.getMaterialSupplierName()));
            infoList.add(vo.getSignTime() == null ? "" : vo.getSignTime());
            infoList.add(getNotNullOfStringInfo(vo.getProductNo()));
            infoList.add(getNotNullOfStringInfo(vo.getSpecNo()));
            infoList.add(getNotNullOfStringInfo(vo.getChineseName()));
            infoList.add(getNotNullOfStringInfo(vo.getChineseDesc()));
            infoList.add(getNotNullOfStringInfo(vo.getEnglishDesc()));
            infoList.add(getNotNullOfStringInfo(vo.getNormExplain()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getAmount()));
            infoList.add(getNotNullOfStringInfo(vo.getCurrency()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getPrice()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getProductUnitPrice()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getBenchmarkPrice()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getDifferentialPrice()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getCostDown()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getOtherCost()));
            infoList.add(getNotNullOfStringInfo(vo.getMemoOfCost()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getPriceSubtotal()));
            infoList.add(vo.getRequestDeliveryDate() == null ? "" : vo.getRequestDeliveryDate());
            infoList.add(getNotNullOfStringInfo(vo.getExecutorName()));
            infoList.add(getNotNullOfStringInfo(vo.getSalesmanName()));
            infoList.add(getNotNullOfStringInfo(vo.getTaxIncluded()));
            infoList.add(getNotNullOfStringInfo(vo.getShipmentNo()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getPlanAmount()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getUnPlanAmount()));
            infoList.add(getNotNullOfStringInfo(vo.getBillNo()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getProductNum()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getUnProductNum()));
            if(StringUtil.isNotEmpty(vo.getAmount())){
                amount = amount.add(vo.getAmount());
            }
            if(StringUtil.isNotEmpty(vo.getPriceSubtotal())){
                priceSubtotal = priceSubtotal.add(vo.getPriceSubtotal());
            }
            if(StringUtil.isNotEmpty(vo.getPlanAmount())){
                planAmount = planAmount.add(vo.getPlanAmount());
            }
            if(StringUtil.isNotEmpty(vo.getUnPlanAmount())){
                unPlanAmount = unPlanAmount.add(vo.getUnPlanAmount());
            }
            if(StringUtil.isNotEmpty(vo.getProductNum())){
                productNum = productNum.add(vo.getProductNum());
            }
            if(StringUtil.isNotEmpty(vo.getUnProductNum())){
                unProductNum = unProductNum.add(vo.getUnProductNum());
            }

            data.add(infoList);
        }
        //合计
        JSONArray customerInfoList = new JSONArray();
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add(amount);
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add(priceSubtotal);
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add(planAmount);
        customerInfoList.add(unPlanAmount);
        customerInfoList.add("");
        customerInfoList.add(productNum);
        customerInfoList.add(unProductNum);

        data.add(customerInfoList);

    }

    /**
     * 获取String类型不为空数据
     * @param value 目标数据
     * @return 不为空数据
     */
    private String getNotNullOfStringInfo(String value){
        if(StringUtils.isEmpty(value)){
            return "";
        }else {
            return value;
        }
    }

    /**
     * 获取BigDecimal类型不为空的数据
     * @param value 目标数据
     * @return 不为空数据
     */
    private BigDecimal getNotNullOfBigDecimalInfo(BigDecimal value){
        if(StringUtil.isNotEmpty(value)){
            return value;
        }else {
            return new BigDecimal("0");
        }
    }

    /**
     * 处理采购统计数据
     * @param statisticsPurchaseInfo 采购统计数据
     * @return 处理后的采购统计数据
     */
    private List<StatisticsPurchaseInfoVo> getPurchaseStatisticsData(List<StatisticsPurchaseInfoRsp> statisticsPurchaseInfo){
        //初始化回参对象集合
        List<StatisticsPurchaseInfoVo> voList = new ArrayList<>();
        for (StatisticsPurchaseInfoRsp infoRsp : statisticsPurchaseInfo) {
            //初始化回参对象
            StatisticsPurchaseInfoVo infoVo = new StatisticsPurchaseInfoVo();
            //赋值
            BeanUtils.copyProperties(infoRsp, infoVo);

            //日期转换
            infoVo.setSignTime(DateUtils.format(infoRsp.getSignTime()));
            infoVo.setRequestDeliveryDate(DateUtils.format(infoRsp.getRequestDeliveryDate()));
            //采购数量
            BigDecimal amount = new BigDecimal("0");
            if (StringUtil.isNotEmpty(infoRsp.getAmount())) {
                amount = infoRsp.getAmount();
            }
            //已计划数量
            BigDecimal planAmount = new BigDecimal("0");
            if (StringUtil.isNotEmpty(infoRsp.getPlanAmount())) {
                planAmount = infoRsp.getPlanAmount();
            }
            infoVo.setPlanAmount(planAmount);
            //未计划数量
            infoVo.setUnPlanAmount(amount.subtract(planAmount));

            //出运数量
            BigDecimal productNum = new BigDecimal("0");
            if (StringUtil.isNotEmpty(infoRsp.getProductNum())) {
                productNum = infoRsp.getProductNum();
            }
            infoVo.setProductNum(productNum);
            //未出运数量
            infoVo.setUnProductNum(amount.subtract(productNum));

            voList.add(infoVo);
        }

        return voList;
    }

    /**
     * 获取excel的title信息
     * @return excel的title信息
     */
    private JSONArray getTitleInfoOfOneStatistics(){
        JSONArray titleList = new JSONArray();
        titleList.add("采购合同号");
        titleList.add("采购类型");
        titleList.add("价格条款");
        titleList.add("定金比例");
        titleList.add("定金总额");
        titleList.add("备注");
        titleList.add("外销合同号");
        titleList.add("厂商名称");
        titleList.add("素材供应商");
        titleList.add("签约日期");
        titleList.add("产品编码");
        titleList.add("规格编码");
        titleList.add("产品名称");
        titleList.add("中文描述");
        titleList.add("英文描述");
        titleList.add("规格说明");
        titleList.add("产品数量");
        titleList.add("币种");
        titleList.add("采购成本");
        titleList.add("产品单价");

        titleList.add("产品基准价");
        titleList.add("差异单价");
        titleList.add("COST DOWN");

        titleList.add("其它费用");
        titleList.add("费用备注");
        titleList.add("采购金额");
        titleList.add("要求交货日期");
        titleList.add("操作员");
        titleList.add("业务员");
        titleList.add("是否含税");
        titleList.add("出运计划单号");
        titleList.add("已计划数量");
        titleList.add("未计划数量");
        titleList.add("出运明细发票号");
        titleList.add("出运数量");
        titleList.add("未出运数量");

        return titleList;
    }

    private List<StatisticsCarryDetailPaymentVo> getVoList(List<StatisticsCarryDetailPaymentRsp> paymentInfo){
        //初始化回参对象集合
        List<StatisticsCarryDetailPaymentVo> voList = new ArrayList<>();
        for(StatisticsCarryDetailPaymentRsp payment : paymentInfo){
            //初始化回参对象
            StatisticsCarryDetailPaymentVo vo = new StatisticsCarryDetailPaymentVo();
            //赋值
            BeanUtils.copyProperties(payment, vo);
            //发票日期
            vo.setCreateDate(DateUtils.format(payment.getCreateDate()));
            //采购单签约日期
            vo.setPurchaseSigningDateStr(DateUtils.format(payment.getPurchaseSigningDate()));
            //出运日期
            if (null != payment.getTime()) {
                String time = DateUtils.format(payment.getTime());
                vo.setTime(time);
            }
            //付款账期
            int paymentTime = 0;
            if (StringUtils.isNotBlank(payment.getPaymentTime())) {
                paymentTime = Integer.valueOf(payment.getPaymentTime());
            }
            if (payment.getLoadingTime() != null) {
                //进仓装柜日期
                Date loadingTime = payment.getLoadingTime();
                vo.setLoadingTime(DateUtils.format(loadingTime));

                String dueDate = "";
                if (paymentTime == 30 || paymentTime == 60 || paymentTime == 90 || paymentTime == 120) {
                    switch (paymentTime) {
                        case 30:
                            dueDate = DateUtils.addMonth(loadingTime, 1, DateUtils.DATE_PATTERN);
                            break;
                        case 60:
                            dueDate = DateUtils.addMonth(loadingTime, 2, DateUtils.DATE_PATTERN);
                            break;
                        case 90:
                            dueDate = DateUtils.addMonth(loadingTime, 3, DateUtils.DATE_PATTERN);
                            break;
                        case 120:
                            dueDate = DateUtils.addMonth(loadingTime, 4, DateUtils.DATE_PATTERN);
                            break;
                    }
                } else {
                    dueDate = DateUtils.plusDay(paymentTime, payment.getLoadingTime(), DateUtils.DATE_PATTERN);
                }
                //应付日期 = 进仓装柜日期 + 付款账期(如果账期为30、60、90、120天，则按月份累加)
                vo.setDueDate(dueDate);

            }
            //应付总额
            BigDecimal paymentAmount = new BigDecimal("0");
            if(StringUtil.isNotEmpty(payment.getPaymentAmount())){
                paymentAmount = payment.getPaymentAmount().setScale(2, BigDecimal.ROUND_HALF_UP);
                vo.setPaymentAmount(paymentAmount);
            }
            //采购单申请比例
            BigDecimal earnestRate = new BigDecimal("0");
            if(StringUtil.isNotEmpty(payment.getEarnestRate())){
                earnestRate = payment.getEarnestRate();
            }
            //出运实际应付 = 应付总额*(100-采购单申请比例)/100
            BigDecimal tempNum = new BigDecimal("100");
            if(earnestRate.compareTo(tempNum) == 0){
                vo.setCarryPayment(new BigDecimal("0"));
                vo.setUnPayment(new BigDecimal("0"));
            }else {
                BigDecimal subNum = tempNum.subtract(earnestRate);
                //出运实际应付
                BigDecimal carryPayment = paymentAmount.multiply(subNum).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);
                vo.setCarryPayment(carryPayment);

                //累计已付
                BigDecimal amount = new BigDecimal("0");
                if(StringUtil.isNotEmpty(payment.getAmount())){
                    amount = payment.getAmount();
                }

                //未付金额 = 实际应付-累计已付
                vo.setUnPayment(carryPayment.subtract(amount).setScale(2, BigDecimal.ROUND_HALF_UP));
            }
            // 预付款金额(应付总额-出运实际应付)
            BigDecimal result = vo.getPaymentAmount().subtract(vo.getCarryPayment());
            vo.setAdvancePaymentAmount(result.setScale(2,BigDecimal.ROUND_HALF_UP));

            voList.add(vo);
        }

        //预付款总金额
        BigDecimal advancePaymentAmountSum = voList.stream().map(p -> p.getAdvancePaymentAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);

        for (StatisticsCarryDetailPaymentVo p: voList) {
            //预付款已付金额
            if (p.getAmountSUM()==null){
                // 条件：已付金额=0  查不到
                // 预付款已付金额=0
                p.setPrepaymentPaidAmount(new BigDecimal(0));
            }else if (advancePaymentAmountSum.compareTo(p.getAmountSUM()) == 1){
                //条件：预付款总额-已付金额>0
                // 预付款金额/预付款总额*已付款金额=预付款已付金额
                BigDecimal result = p.getAdvancePaymentAmount().divide(advancePaymentAmountSum, 8,BigDecimal.ROUND_HALF_UP).multiply(p.getAmountSUM());
                p.setPrepaymentPaidAmount(result.setScale(2,BigDecimal.ROUND_HALF_UP));
            }else if (advancePaymentAmountSum.compareTo(p.getAmountSUM()) == 0){
                //条件：预付款总额-已付金额=0
                // 预付款已付金额=预付款金额
                p.setPrepaymentPaidAmount(p.getAmountSUM());
            }
        }

        return voList;
    }
    /**
     * 按出运明细统计采购付款信息
     * @param req 查询参数对象
     * @return 按出运明细统计采购付款信息
     */
    public PageInfo<StatisticsCarryDetailPaymentVo> getStatisticsCarryDetailPaymentByPage(CarryDetailStatisticsPaymentReq req) {
        //获取统计信息
        List<StatisticsCarryDetailPaymentRsp> paymentInfo = carryDetailService.getStatisticsCarryDetailPaymentInfo(req);
        //初始化回参对象集合
        List<StatisticsCarryDetailPaymentVo> voList = new ArrayList<>();
        if (CollectionUtils.isEmpty(paymentInfo)) {
            PageInfo pageInfo = new PageInfo();
            pageInfo.setList(voList);
            return pageInfo;
        }
        PageInfo pageInfo = new PageInfo(paymentInfo);
        pageInfo.setList(getVoList(paymentInfo));
        return pageInfo;
    }

    /**
     * 供应商出货详情统计--集合
     * @param req 查询参数对象
     * @return 按出运明细统计采购付款信息
     */
    private List<StatisticShippingDetailRsp> shippingDetailRspList(statisticShippingDetailReq req){
        List<StatisticShippingDetailRsp> shippingDetailRspList=carryDetailService.getShippingDetailByPage(req);
        for (StatisticShippingDetailRsp p:shippingDetailRspList) {
            p.setInvoiceDateStr(DateUtils.format(p.getInvoiceDate(),DateUtils.DATE_PATTERN));
            p.setInStockDateStr(DateUtils.format(p.getInStockDate(),DateUtils.DATE_PATTERN));
            p.setActualDismissalTimeStr(DateUtils.format(p.getActualDismissalTime(),DateUtils.DATE_PATTERN));
            p.setShippingStr(DateUtils.format(p.getShippingDate(),DateUtils.DATE_PATTERN));
            p.setRequestDeliveryDateStr(DateUtils.format(p.getRequestDeliveryDate(),DateUtils.DATE_PATTERN));
            p.setSigningDateStr(DateUtils.format(p.getSigningDate(),DateUtils.DATE_PATTERN));
            switch (p.getStatus()){
                case 1:
                    p.setStatusStr("草稿箱");
                    break;
                case 2:
                    p.setStatusStr("待批箱");
                    break;
                case 3:
                    p.setStatusStr("已批箱");
                    break;
                case 4:
                    p.setStatusStr("完成箱");
                    break;
                case 5:
                    p.setStatusStr("垃圾箱");
                    break;
                case 6:
                    p.setStatusStr("终止箱");
                    break;
            }
        }
        return shippingDetailRspList;
    }
    /**
     * 供应商出货详情统计--分页
     * @param req 查询参数对象
     * @return 按出运明细统计采购付款信息
     */
    public PageInfo<StatisticShippingDetailRsp> getShippingDetailByPage(statisticShippingDetailReq req) {
        List<StatisticShippingDetailRsp> shippingDetailRspList=shippingDetailRspList(req);
        PageInfo pageInfo = new PageInfo(shippingDetailRspList);
        return pageInfo;
    }
    /**
     * 供应商出货详情统计--导出
     * @param req 查询参数对象
     * @return 按出运明细统计采购付款信息
     */
    public JSONObject getShippingDetailByPageExport(statisticShippingDetailReq req){
        List<StatisticShippingDetailRsp> paymentInfo = shippingDetailRspList(req);
        JSONObject obj = new JSONObject();
        //获取excel的title信息
        JSONArray titleList = getTitleInfoOfShippingDetailStatistics();
        JSONArray data = new JSONArray();
        data.add(titleList);
        if(CollectionUtils.isEmpty(paymentInfo)){
            obj.put("data", data);
            return obj;
        }
        ExcelInfoShippingDetailExport(data,paymentInfo);
        obj.put("data", data);
        return obj;

    }

    private JSONArray getTitleInfoOfShippingDetailStatistics(){
        JSONArray obj=new JSONArray();
        obj.add("单据类型");
        obj.add("发票号码");
        obj.add("业务模式");
        obj.add("发票日期");
        obj.add("进仓装柜日期");
        obj.add("实际开船日期ATD");
        obj.add("出运日期");
        obj.add("业务员");
        obj.add("出运操作员");
        obj.add("采购操作员");
        obj.add("产品编码");
        obj.add("规格编码");
        obj.add("供应商名称");
        obj.add("外销合同号");
        obj.add("外销签约日期");
        obj.add("采购单号");
        obj.add("出运数量");
        obj.add("采购数量");
        obj.add("要求交货日期");
        obj.add("供应商反馈交期");
        obj.add("实际交期");
        obj.add("反馈备注");
        obj.add("产品类型");
        return obj;
    }
    private void ExcelInfoShippingDetailExport(JSONArray data, List<StatisticShippingDetailRsp> list){
        for(StatisticShippingDetailRsp vo : list) {
            JSONArray infoList = new JSONArray();
            infoList.add(getNotNullOfStringInfo(vo.getStatusStr()));
            infoList.add(getNotNullOfStringInfo(vo.getInvoiceCode()));
            infoList.add(getNotNullOfStringInfo(vo.getBusinessModelName()));
            infoList.add(getNotNullOfStringInfo(vo.getInvoiceDateStr()));
            infoList.add(getNotNullOfStringInfo(vo.getInStockDateStr()));
            infoList.add(getNotNullOfStringInfo(vo.getActualDismissalTimeStr()));
            infoList.add(getNotNullOfStringInfo(vo.getShippingStr()));
            infoList.add(getNotNullOfStringInfo(vo.getSalesmanName()));
            infoList.add(getNotNullOfStringInfo(vo.getOperatorName()));
            infoList.add(getNotNullOfStringInfo(vo.getOperationNamePurchase()));
            infoList.add(getNotNullOfStringInfo(vo.getProductCode()));
            infoList.add(getNotNullOfStringInfo(vo.getSpecificationCode()));
            infoList.add(getNotNullOfStringInfo(vo.getSupplierName()));
            infoList.add(getNotNullOfStringInfo(vo.getSalesContractNo()));
            infoList.add(getNotNullOfStringInfo(vo.getSigningDateStr()));
            infoList.add(getNotNullOfStringInfo(vo.getPurchaseOrderNo()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getCarryProductNum()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getPurchaseProductNum()));
            infoList.add(getNotNullOfStringInfo(vo.getRequestDeliveryDateStr()));
            infoList.add(getNotNullOfStringInfo(vo.getFeedbackDeliveryDate()));
            infoList.add(getNotNullOfStringInfo(vo.getActualDeliveryDate()));
            infoList.add(getNotNullOfStringInfo(vo.getDescription()));
            infoList.add(getNotNullOfStringInfo(vo.getProType()));
            data.add(infoList);
        }

    }





    /**
     * 按出运明细统计采购付款信息-导出
     * @param req
     * @return
     */
    public JSONObject getStatisticsCarryDetailPaymentExport(CarryDetailStatisticsPaymentReq req){
        //获取统计信息
        List<StatisticsCarryDetailPaymentRsp> paymentInfo = carryDetailService.getStatisticsCarryDetailPaymentInfo(req);
        //初始化回参对象集合
        List<StatisticsCarryDetailPaymentVo> voList = getVoList(paymentInfo);

        JSONObject obj = new JSONObject();
        //获取excel的title信息
        JSONArray titleList = getTitleInfoCarryDetailPayment();
        JSONArray data = new JSONArray();
        data.add(titleList);
        if(CollectionUtils.isEmpty(voList)){
            obj.put("data", data);
            return obj;
        }
        ExcelInfoCarryDetailPayment(data,voList);
        obj.put("data", data);
        return obj;

    }
    public JSONArray getTitleInfoCarryDetailPayment(){
        JSONArray obj=new JSONArray();
        obj.add("序号");
        obj.add("出运发票号");
        obj.add("签约公司");
        obj.add("采购合同号");
        obj.add("采购单签约日期");
        obj.add("厂商名称");
        obj.add("是否含税");
        obj.add("外销合同号");
        obj.add("出运日期");
        obj.add("进仓装柜日期");
        obj.add("产品编码");
        obj.add("规格编码");
        obj.add("产品中文名");
        obj.add("产品中文描述");
        obj.add("付款账期");
        obj.add("应付日期");
        obj.add("币种");
        obj.add("业务员");
        obj.add("数量");
        obj.add("成本");
        obj.add("应付总额");
        obj.add("采购单申请比例");
        obj.add("出运实际应付");
        obj.add("预付款金额");
        obj.add("预付款已付金额");
        obj.add("出运操作员");
        obj.add("采购操作员");
        obj.add("申请金额");
        obj.add("累计已付");
        obj.add("未付金额");
        obj.add("类型");
        obj.add("业务模式");
        return obj;
    }
    public void ExcelInfoCarryDetailPayment(JSONArray data, List<StatisticsCarryDetailPaymentVo> list){
        //产品数量
        BigDecimal productNum = new BigDecimal("0");
        //应付总额
        BigDecimal paymentAmount = new BigDecimal("0");
        //出运实际应付
        BigDecimal carryPayment = new BigDecimal("0");
        //申请金额
        BigDecimal applicationAmount = new BigDecimal("0");
        //累计已付
        BigDecimal amount = new BigDecimal("0");
        //未付金额
        BigDecimal unPayment = new BigDecimal("0");

        //预付款金额
        BigDecimal advancePaymentAmount = new BigDecimal("0");
        //预付款已付金额
        BigDecimal prepaymentPaidAmount = new BigDecimal("0");

        Integer i=0;
        for(StatisticsCarryDetailPaymentVo vo : list) {
            JSONArray infoList = new JSONArray();
            infoList.add(++i);
            infoList.add(getNotNullOfStringInfo(vo.getBillNo()));
            infoList.add(getNotNullOfStringInfo(vo.getCompanyName()));
            infoList.add(getNotNullOfStringInfo(vo.getPurchaseNo()));
            infoList.add(getNotNullOfStringInfo(vo.getPurchaseSigningDateStr()));
            infoList.add(getNotNullOfStringInfo(vo.getSupplierName()));
            infoList.add(getNotNullOfStringInfo(vo.getTaxIncluded()));
            infoList.add(getNotNullOfStringInfo(vo.getSaleContractNo()));
            infoList.add(getNotNullOfStringInfo(vo.getTime()));
            infoList.add(getNotNullOfStringInfo(vo.getLoadingTime()));
            infoList.add(getNotNullOfStringInfo(vo.getProductCode()));
            infoList.add(getNotNullOfStringInfo(vo.getSpecNo()));
            infoList.add(getNotNullOfStringInfo(vo.getProductCName()));
            infoList.add(getNotNullOfStringInfo(vo.getProductCDesc()));
            infoList.add(getNotNullOfStringInfo(vo.getPaymentTime()));
            infoList.add(getNotNullOfStringInfo(vo.getDueDate()));
            infoList.add(getNotNullOfStringInfo(vo.getCurrency()));
            infoList.add(getNotNullOfStringInfo(vo.getSalesmanName()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getProductNum()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getCostUnitPrice()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getPaymentAmount()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getEarnestRate()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getCarryPayment()));

            infoList.add(getNotNullOfBigDecimalInfo(vo.getAdvancePaymentAmount()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getPrepaymentPaidAmount()));

            infoList.add(getNotNullOfStringInfo(vo.getOperator()));
            infoList.add(getNotNullOfStringInfo(vo.getOperationNamePurchase()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getApplicationAmount()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getAmount()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getUnPayment()));
            infoList.add(getNotNullOfStringInfo(vo.getProductType()));
            infoList.add(getNotNullOfStringInfo(vo.getBusinessModelName()));

            if(StringUtil.isNotEmpty(vo.getProductNum())){
                productNum = productNum.add(vo.getProductNum());
            }
            if(StringUtil.isNotEmpty(vo.getPaymentAmount())){
                paymentAmount = paymentAmount.add(vo.getPaymentAmount());
            }
            if(StringUtil.isNotEmpty(vo.getCarryPayment())){
                carryPayment = carryPayment.add(vo.getCarryPayment());
            }
            if(StringUtil.isNotEmpty(vo.getApplicationAmount())){
                applicationAmount = applicationAmount.add(vo.getApplicationAmount());
            }
            if(StringUtil.isNotEmpty(vo.getAmount())){
                amount = amount.add(vo.getAmount());
            }
            if(StringUtil.isNotEmpty(vo.getUnPayment())){
                unPayment = unPayment.add(vo.getUnPayment());
            }
            if(StringUtil.isNotEmpty(vo.getAdvancePaymentAmount())){
                advancePaymentAmount = advancePaymentAmount.add(vo.getAdvancePaymentAmount());
            }
            if(StringUtil.isNotEmpty(vo.getPrepaymentPaidAmount())){
                prepaymentPaidAmount = prepaymentPaidAmount.add(vo.getPrepaymentPaidAmount());
            }
            data.add(infoList);
        }
        //合计
        JSONArray customerInfoList = new JSONArray();
        customerInfoList.add("合计");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add(productNum);
        customerInfoList.add("");
        customerInfoList.add(paymentAmount);
        customerInfoList.add("");
        customerInfoList.add(carryPayment);
        customerInfoList.add(advancePaymentAmount);
        customerInfoList.add(prepaymentPaidAmount);
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add(applicationAmount);
        customerInfoList.add(amount);
        customerInfoList.add(unPayment);
        customerInfoList.add("");
        customerInfoList.add("");

        data.add(customerInfoList);

    }
    /**
     * 采购排产及计划统计
     * @param req
     * @return
     */
    public PageInfo<PurchaseStatisticsTwoRes> getStatisticsTwoPurchaseInfo(PurchaseStatisticsTwoReq req){
        List<PurchaseStatisticsTwoRes> purchaseStatisticsTwoResList=purchaseStatisticsTwoResList(req);
        PageInfo<PurchaseStatisticsTwoRes> pageInfo=new PageInfo<>(purchaseStatisticsTwoResList);
        return pageInfo;
    }

    /**
     * 获取采购排产及计划统计集合
     * @param req
     * @return
     */
    public List<PurchaseStatisticsTwoRes> purchaseStatisticsTwoResList(PurchaseStatisticsTwoReq req){
        List<PurchaseStatisticsTwoRes> purchaseStatisticsTwoResList=carryDetailService.getStatisticsTwoPurchaseInfo(req);
        for (PurchaseStatisticsTwoRes p:purchaseStatisticsTwoResList){
            p.setSigningDateStr(DateUtils.format(p.getSigningDate(),DateUtils.DATE_PATTERN));
            p.setRequestDeliveryDateStr(DateUtils.format(p.getRequestDeliveryDate(),DateUtils.DATE_PATTERN));
            p.setFeedbackDeliveryDateStr(DateUtils.format(p.getFeedbackDeliveryDate(),DateUtils.DATE_PATTERN));
            p.setActualDeliveryDateStr(DateUtils.format(p.getActualDeliveryDate(),DateUtils.DATE_PATTERN));
            switch (p.getProductType()){
                case "1":
                    p.setProductType("成品");
                    break;
                case "2":
                    p.setProductType("配件");
                    break;
                case "3":
                    p.setProductType("备货");
                    break;
                case "4":
                    p.setProductType("外销");
                    break;
                case "5":
                    p.setProductType("样品采购");
                    break;
            }

            if (StringUtils.isNotEmpty(p.getStatus())){
                switch (p.getStatus()){
                    case "1":
                        p.setStatus("草稿箱");
                        break;
                    case "2":
                    case "2.1":
                        p.setStatus("待批箱");
                        break;
                    case "3":
                        p.setStatus("已批箱");
                        break;
                    case "4":
                        p.setStatus("完成箱");
                        break;
                    case "5":
                        p.setStatus("垃圾箱");
                        break;
                    case "6":
                        p.setStatus("终止箱");
                        break;
                }
            }
            if (StringUtils.isNotEmpty(p.getTaxIncluded())){
                switch (p.getTaxIncluded()){
                    case "1":
                        p.setTaxIncluded("含税出厂价");
                        break;
                    case "2":
                        p.setTaxIncluded("未税出厂价");
                        break;
                    case "3":
                        p.setTaxIncluded("含税FOB价");
                        break;
                    case "4":
                        p.setTaxIncluded("未税FOB价");
                        break;
                    default:
                        p.setTaxIncluded("");
                }
            }
            p.setUnDeliveredTotal(p.getPurchaseCost().multiply(p.getUnPlanAmount()));
        }
        return purchaseStatisticsTwoResList;
    }

    public JSONObject getStatisticsTwoPurchaseInfoExport(PurchaseStatisticsTwoReq req){
        List<PurchaseStatisticsTwoRes> purchaseStatisticsTwoResList=purchaseStatisticsTwoResList(req);
        JSONObject obj = new JSONObject();
        //获取excel的title信息
        JSONArray titleList = getTitleInfoOfTwoStatistics();
        JSONArray data = new JSONArray();
        data.add(titleList);
        if(CollectionUtils.isEmpty(purchaseStatisticsTwoResList)){
            obj.put("data", data);
            return obj;
        }
        ExcelInfoExport(data,purchaseStatisticsTwoResList);
        obj.put("data", data);
        return obj;
    }
    public JSONArray getTitleInfoOfTwoStatistics(){
        JSONArray obj=new JSONArray();
        obj.add("序号");
        obj.add("单据类型");
        obj.add("下单人");
        obj.add("业务员");
        obj.add("签约公司");
        obj.add("价格条款");
        obj.add("是否含税");
        obj.add("定金比例");
        obj.add("定金总额");
        obj.add("客户简称");
        obj.add("中文名称");
        obj.add("中文描述");
        obj.add("英文描述");
        obj.add("客户等级");
        obj.add("下单日期");
        obj.add("供应商反馈交期");
        obj.add("发货日期");
        obj.add("实际交期");
        obj.add("要求交货期");
        obj.add("出运计划发票号");
        obj.add("出运明细发票号");
        obj.add("采购单号");
        obj.add("供应商名称");
        obj.add("是否第一次");
        obj.add("PO NO.");
        obj.add("产品编码");
        obj.add("素材供应商");
        obj.add("源产品编码");
        obj.add("规格编码");
        obj.add("订单数量");
        obj.add("已交货数量");
        obj.add("未交货数量");
        obj.add("采购成本");
        obj.add("未交货产品总额");
        obj.add("成本金额小计");
        obj.add("采购类型");
        obj.add("采购备注");
        obj.add("反馈备注");
        return obj;
    }
    public void ExcelInfoExport(JSONArray data, List<PurchaseStatisticsTwoRes> list){
        //订单数量
        BigDecimal amount = new BigDecimal("0");
        //已交货数量
        BigDecimal planAmount = new BigDecimal("0");
        //未交货数量
        BigDecimal unPlanAmount = new BigDecimal("0");
        //成本金额小计
        BigDecimal priceSubtotal = new BigDecimal("0");

        //采购成本
        BigDecimal purchaseCost = new BigDecimal("0");
        //未交货产品总额
        BigDecimal unDeliveredTotal = new BigDecimal("0");

        Integer i=0;
        for(PurchaseStatisticsTwoRes vo : list) {
            JSONArray infoList = new JSONArray();
            infoList.add(++i);
            infoList.add(getNotNullOfStringInfo(vo.getStatus()));
            infoList.add(getNotNullOfStringInfo(vo.getOperationName()));
            infoList.add(getNotNullOfStringInfo(vo.getSalesmanName()));
            infoList.add(getNotNullOfStringInfo(vo.getSigningCompanyName()));
            infoList.add(getNotNullOfStringInfo(vo.getPaymentType()));
            infoList.add(getNotNullOfStringInfo(vo.getTaxIncluded()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getEarnestRate()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getEarnestMoney()));
            infoList.add(getNotNullOfStringInfo(vo.getAbbreviation()));
            infoList.add(getNotNullOfStringInfo(vo.getChineseName()));
            infoList.add(getNotNullOfStringInfo(vo.getChineseDesc()));
            infoList.add(getNotNullOfStringInfo(vo.getEnglishDesc()));
            infoList.add(getNotNullOfStringInfo(vo.getCustomerLevelName()));
            infoList.add(getNotNullOfStringInfo(vo.getSigningDateStr()));
            infoList.add(getNotNullOfStringInfo(vo.getFeedbackDeliveryDateStr()));
            infoList.add(getNotNullOfStringInfo(vo.getDeliveryDateTypeStr()));
            infoList.add(getNotNullOfStringInfo(vo.getActualDeliveryDateStr()));
            infoList.add(getNotNullOfStringInfo(vo.getRequestDeliveryDateStr()));
            infoList.add(getNotNullOfStringInfo(vo.getShipmentNo()));
            infoList.add(getNotNullOfStringInfo(vo.getInvoiceNo()));
            infoList.add(getNotNullOfStringInfo(vo.getPurchaseNo()));
            infoList.add(getNotNullOfStringInfo(vo.getSupplierName()));
            infoList.add(getNotNullOfStringInfo(vo.getIsFirstTime()));
            infoList.add(getNotNullOfStringInfo(vo.getContractNo()));
            infoList.add(getNotNullOfStringInfo(vo.getProductNo()));
            infoList.add(getNotNullOfStringInfo(vo.getMaterialSupplier()));
            infoList.add(getNotNullOfStringInfo(vo.getSourceProductNo()));
            infoList.add(getNotNullOfStringInfo(vo.getSpecNo()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getAmount()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getPlanAmount()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getUnPlanAmount()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getPurchaseCost()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getUnDeliveredTotal()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getPriceSubtotal()));
            infoList.add(getNotNullOfStringInfo(vo.getProductType()));
            infoList.add(getNotNullOfStringInfo(vo.getRemark()));
            infoList.add(getNotNullOfStringInfo(vo.getDescription()));
            if(StringUtil.isNotEmpty(vo.getAmount())){
                amount = amount.add(vo.getAmount());
            }
            if(StringUtil.isNotEmpty(vo.getPlanAmount())){
                planAmount = planAmount.add(vo.getPlanAmount());
            }
            if(StringUtil.isNotEmpty(vo.getUnPlanAmount())){
                unPlanAmount = unPlanAmount.add(vo.getUnPlanAmount());
            }
            if(StringUtil.isNotEmpty(vo.getPriceSubtotal())){
                priceSubtotal = priceSubtotal.add(vo.getPriceSubtotal());
            }

            if(StringUtil.isNotEmpty(vo.getPurchaseCost())){
                purchaseCost = purchaseCost.add(vo.getPurchaseCost());
            }
            if(StringUtil.isNotEmpty(vo.getUnDeliveredTotal())){
                unDeliveredTotal = unDeliveredTotal.add(vo.getUnDeliveredTotal());
            }

            data.add(infoList);
        }

        Map<String, List<PurchaseStatisticsTwoRes>> listMap = list.stream().
                filter(p -> StringUtils.isNotEmpty(p.getPurchaseNo())).
                collect(Collectors.groupingBy(p -> p.getPurchaseNo()));

        //合计
        JSONArray customerInfoList = new JSONArray();
        customerInfoList.add("合计");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("采购单号出现次数："+listMap.size());
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add(amount);
        customerInfoList.add(planAmount);
        customerInfoList.add(unPlanAmount);
        customerInfoList.add(purchaseCost);
        customerInfoList.add(unDeliveredTotal);
        customerInfoList.add(priceSubtotal);
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");

        data.add(customerInfoList);
    }

    /**
     * 已做明细未结汇--集合
     * @param req
     * @return
     */
    public List<DetailUnBillExchangeRsq> detailUnBillExchangeList(DetailUnBillExchangeReq req){
        List<DetailUnBillExchangeRsq> detailUnBillExchangeList=carryDetailService.detailUnBillExchangeList(req);
        for (DetailUnBillExchangeRsq p:detailUnBillExchangeList){
            p.setShippingStr(DateUtils.format(p.getShippingDate(),DateUtils.DATE_PATTERN));
            p.setInStockDateStr(DateUtils.format(p.getInStockDate(),DateUtils.DATE_PATTERN));
            p.setActualDismissalTimeStr(DateUtils.format(p.getActualDismissalTime(),DateUtils.DATE_PATTERN));
            p.setCreateTimeStr(DateUtils.format(p.getCreateTime(),DateUtils.DATE_PATTERN));
        }

       return detailUnBillExchangeList;
    }
    /**
     * 已做明细未结汇--分页
     * @param req
     * @return
     */
    public PageInfo<DetailUnBillExchangeRsq> detailUnBillExchangeByPage(DetailUnBillExchangeReq req){
        List<DetailUnBillExchangeRsq> detailUnBillExchangeList=detailUnBillExchangeList(req);
        PageInfo<DetailUnBillExchangeRsq> pageInfo=new PageInfo<>(detailUnBillExchangeList);
        return pageInfo;
    }

    /**
     * 已做明细未结汇--导出
     * @param req
     * @return
     */
    public JSONObject detailUnBillExchangeExport(DetailUnBillExchangeReq req){
        List<DetailUnBillExchangeRsq> detailUnBillExchangeList=detailUnBillExchangeList(req);

        JSONObject obj = new JSONObject();
        //获取excel的title信息
        JSONArray titleList = getTitleInfoOfThreeStatistics();
        JSONArray data = new JSONArray();
        data.add(titleList);
        if(CollectionUtils.isEmpty(detailUnBillExchangeList)){
            obj.put("data", data);
            return obj;
        }
        ExcelInfoThreeExport(data,detailUnBillExchangeList);
        obj.put("data", data);
        return obj;
    }
    public JSONArray getTitleInfoOfThreeStatistics(){
        JSONArray obj=new JSONArray();
        obj.add("序号");
        obj.add("出运发票号");
        obj.add("业务模式");
        obj.add("价格术语");
        obj.add("出运日期");
        obj.add("进仓装柜日期");
        obj.add("实际开船日期ATD");
        obj.add("制单日期");
        obj.add("操作员");
        obj.add("业务员");
        obj.add("产品编码");
        obj.add("规格编码");
        obj.add("销售合同号");
        obj.add("出运明细数量");
        obj.add("结汇数量");
        obj.add("未结数量");
        obj.add("结汇发票号");
        return obj;
    }

    public void ExcelInfoThreeExport(JSONArray data, List<DetailUnBillExchangeRsq> list){
        //出运明细数量
        BigDecimal carryDetailNum = new BigDecimal("0");
        //结汇数量
        BigDecimal billExchangeInfoNum = new BigDecimal("0");
        //未结数量
        BigDecimal unBillExchangeInfoNum = new BigDecimal("0");
        Integer i=0;
        for(DetailUnBillExchangeRsq vo : list) {
            JSONArray infoList = new JSONArray();
            infoList.add(++i);
            infoList.add(getNotNullOfStringInfo(vo.getInvoiceCode()));
            infoList.add(getNotNullOfStringInfo(vo.getBusinessModelName()));
            infoList.add(getNotNullOfStringInfo(vo.getPriceTermName()));
            infoList.add(getNotNullOfStringInfo(vo.getShippingStr()));
            infoList.add(getNotNullOfStringInfo(vo.getInStockDateStr()));
            infoList.add(getNotNullOfStringInfo(vo.getActualDismissalTimeStr()));
            infoList.add(getNotNullOfStringInfo(vo.getCreateTimeStr()));
            infoList.add(getNotNullOfStringInfo(vo.getOperationName()));
            infoList.add(getNotNullOfStringInfo(vo.getSalesmanName()));
            infoList.add(getNotNullOfStringInfo(vo.getProductCode()));
            infoList.add(getNotNullOfStringInfo(vo.getSpecificationCode()));
            infoList.add(getNotNullOfStringInfo(vo.getSalesContractNo()));

            infoList.add(getNotNullOfBigDecimalInfo(vo.getCarryDetailNum()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getBillExchangeInfoNum()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getUnBillExchangeInfoNum()));
            infoList.add(getNotNullOfStringInfo(vo.getBillExchangeNo()));

            if(StringUtil.isNotEmpty(vo.getCarryDetailNum())){
                carryDetailNum = carryDetailNum.add(vo.getCarryDetailNum());
            }
            if(StringUtil.isNotEmpty(vo.getBillExchangeInfoNum())){
                billExchangeInfoNum = billExchangeInfoNum.add(vo.getBillExchangeInfoNum());
            }
            if(StringUtil.isNotEmpty(vo.getUnBillExchangeInfoNum())){
                unBillExchangeInfoNum = unBillExchangeInfoNum.add(vo.getUnBillExchangeInfoNum());
            }
            data.add(infoList);
        }
        //合计
        JSONArray customerInfoList = new JSONArray();
        customerInfoList.add("合计");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add("");
        customerInfoList.add(carryDetailNum);
        customerInfoList.add(billExchangeInfoNum);
        customerInfoList.add(unBillExchangeInfoNum);
        customerInfoList.add("");

        data.add(customerInfoList);
    }
    /**
     * 已出运未结汇（物流）--集合
     * @param req
     * @return
     */
    private List<DetailShippedUnExchangeRsp> detailShippedUnExchangeList(DetailShippedUnExchangeReq req){
        List<DetailShippedUnExchangeRsp> list=carryDetailService.detailShippedUnExchangeList(req);
        for (DetailShippedUnExchangeRsp p:list){
            p.setCreateTimeStr(DateUtils.format(p.getCreateTime(),DateUtils.DATE_PATTERN));
            p.setShippingDateStr(DateUtils.format(p.getShippingDate(),DateUtils.DATE_PATTERN));
            p.setInStockDateStr(DateUtils.format(p.getInStockDate(),DateUtils.DATE_PATTERN));
            p.setActualDismissalTimeStr(DateUtils.format(p.getActualDismissalTime(),DateUtils.DATE_PATTERN));
        }
        return list;
    }

    /**
     * 已出运未结汇（物流）--分页
     * @param req
     * @return
     */
    public PageInfo<DetailShippedUnExchangeRsp> detailShippedUnExchangeByPage(DetailShippedUnExchangeReq req){
        List<DetailShippedUnExchangeRsp> list=detailShippedUnExchangeList(req);
        PageInfo pageInfo=new PageInfo(list);
        return pageInfo;
    }


    /**
     * 已出运未结汇（物流）--导出
     * @param req
     * @return
     */
    public JSONObject detailShippedUnExchangeExport(DetailShippedUnExchangeReq req){
        List<DetailShippedUnExchangeRsp> list=detailShippedUnExchangeList(req);

        JSONObject obj = new JSONObject();
        //获取excel的title信息
        JSONArray titleList = getTitleDetailShippedUnExchange();
        JSONArray data = new JSONArray();
        data.add(titleList);
        if(CollectionUtils.isEmpty(list)){
            obj.put("data", data);
            return obj;
        }
        ExcelDetailShippedUnExchange(data,list);
        obj.put("data", data);
        return obj;
    }
    public JSONArray getTitleDetailShippedUnExchange(){
        JSONArray obj=new JSONArray();
        obj.add("出运发票号");
        obj.add("结汇发票号");
        obj.add("是否完成");
        obj.add("价格术语");
        obj.add("操作员");
        obj.add("业务员");
        obj.add("制单日期");
        obj.add("进仓装柜日期");
        obj.add("实际开船日期ATD");
        obj.add("出运日期");
        obj.add("业务模式");
        return obj;
    }

    public void ExcelDetailShippedUnExchange(JSONArray data, List<DetailShippedUnExchangeRsp> list){
        for(DetailShippedUnExchangeRsp vo : list) {
            JSONArray infoList = new JSONArray();
            infoList.add(getNotNullOfStringInfo(vo.getInvoiceCode()));
            infoList.add(getNotNullOfStringInfo(vo.getBillExchangeNo()));
            infoList.add(getNotNullOfStringInfo(vo.getIsDone()));
            infoList.add(getNotNullOfStringInfo(vo.getPriceTermName()));
            infoList.add(getNotNullOfStringInfo(vo.getOperationName()));
            infoList.add(getNotNullOfStringInfo(vo.getSalesmanName()));
            infoList.add(getNotNullOfStringInfo(vo.getCreateTimeStr()));
            infoList.add(getNotNullOfStringInfo(vo.getInStockDateStr()));
            infoList.add(getNotNullOfStringInfo(vo.getActualDismissalTimeStr()));
            infoList.add(getNotNullOfStringInfo(vo.getShippingDateStr()));
            infoList.add(getNotNullOfStringInfo(vo.getBusinessModelName()));
            data.add(infoList);
        }
    }


    /**
     * 出运是否结汇统计
     * @param req 查询参数实体
     * @return 出运是否结汇统计
     */
    public PageInfo<ShipmentIsBillExchangeVo> getShipmentIsBillExchangeByPage(ShipmentIsBillExchangeReq req) {
        if (StringUtils.isNotEmpty(req.getContractNo())) {
            //处理前后空格
            req.setContractNo(req.getContractNo().trim());
        }
        if (StringUtils.isNotEmpty(req.getCarryInvoiceNo())) {
            //处理前后空格
            req.setCarryInvoiceNo(req.getCarryInvoiceNo().trim());
        }
        //调用接口查询结果
        List<ShipmentIsBillExchangeRsp> shipmentIsBillExchange = carryDetailService.getShipmentIsBillExchange(req);
        //初始化回参
        List<ShipmentIsBillExchangeVo> voList = new ArrayList<>();
        //获取分页信息
        PageInfo pageInfo = new PageInfo(shipmentIsBillExchange);
        if (CollectionUtils.isEmpty(shipmentIsBillExchange)) {
            pageInfo.setList(voList);
            return pageInfo;
        }
        //数据封装
        for (ShipmentIsBillExchangeRsp info : shipmentIsBillExchange) {
            //初始化回参对象
            ShipmentIsBillExchangeVo vo = new ShipmentIsBillExchangeVo();
            //字段赋值
            BeanUtils.copyProperties(info, vo);
            //日期处理
            vo.setCreateDate(DateUtils.format(info.getCreateDate()));

            voList.add(vo);
        }

        pageInfo.setList(voList);
        return pageInfo;
    }

    /**
     * 产品、配件终止、取消终止
     * @param req 操作参数实体
     * @return 操作结果
     */
    public R updateProductOrPartsStatus(UpdateProductOrPartsStatusReq req) {
        if (null == req.getId() || null == req.getStatus() || null == req.getType()) {
            return R.buildError(ResultStatusEnum.PARAMETER_ERROR);
        }
        int status = checkDataIsPayment(req.getType(), req.getId());
        if (1 == status) {
            //已做付款,不可终止
            return R.buildError(ResultStatusEnum.PAYMENT_USED);
        }
        if (req.getType() == 1) {
            //产品修改
            //没有做付款,可终止
            CarryDetailProductEntity productUpdate = new CarryDetailProductEntity();
            productUpdate.setId(req.getId());
            productUpdate.setStatus(req.getStatus());
            carryDetailProductService.update(productUpdate);
            //对应配件也进行终止、取消终止
            CarryDetailProductPartsEntity partsQuery = new CarryDetailProductPartsEntity();
            //产品id
            partsQuery.setProductDetailId(req.getId());
            //数据有效
            partsQuery.setValid(DataIsValidEnum.VALID.getId());
            List<CarryDetailProductPartsEntity> carryDetailProductPartsList = carryDetailProductPartsService.queryAll(partsQuery);
            if (CollectionUtils.isEmpty(carryDetailProductPartsList)) {
                return R.build(ResultStatusEnum.SUCCESS);
            }
            for (CarryDetailProductPartsEntity parts : carryDetailProductPartsList) {
                //循环终止、取消终止该产品下的所有配件
                //配件修改
                CarryDetailProductPartsEntity partsUpdate = new CarryDetailProductPartsEntity();
                partsUpdate.setId(parts.getId());
                partsUpdate.setStatus(req.getStatus());
                carryDetailProductPartsService.update(partsUpdate);
            }
        } else {
            //配件修改
            CarryDetailProductPartsEntity partsUpdate = new CarryDetailProductPartsEntity();
            partsUpdate.setId(req.getId());
            partsUpdate.setStatus(req.getStatus());
            carryDetailProductPartsService.update(partsUpdate);
        }
        return R.build(ResultStatusEnum.SUCCESS);
    }

    /**
     * 校验是否被下游调用 0:未被调用 1:付款调用
     * @param type 1:产品修改 2:配件修改
     * @param id 产品、配件id
     * @return 0:未被调用 1:付款调用
     */
    private int checkDataIsPayment(int type, int id) {
        if (1 == type) {
            //产品修改
            //获取已做付款数量
            int count = paymentService.getCountByCarryDetailBillNoOrProductId(null, id);
            if (count == 0) {
                return 0;
            } else {
                return 1;
            }
        } else {
            //配件修改
            //获取配件信息
            CarryDetailProductPartsEntity partsInfo = carryDetailProductPartsService.queryById(id);
            //获取已做付款数量
            int count = paymentService.getCountByCarryDetailBillNoOrProductId(null, partsInfo.getProductDetailId());
            if (count == 0) {
                return 0;
            } else {
                return 1;
            }
        }
    }


    /**
     * 根据 外销合同号 产品编码 查询该产品的剩余数量
     * @param carryPlanNo 出运计划编码
     * @param carryDetailProductId 出运明细产品的id
     * @param exportCode 外销合同号
     * @param productCode 产品编码
     * @param specNo 规格编码
     * @return 剩余数量
     */
    public Integer surplusAmount(String shipmentNo, Integer carryDetailProductId, String exportCode, String productCode, String specNo) {
        return carryDetailService.surplusAmount(shipmentNo, carryDetailProductId, exportCode, productCode, specNo);
    }
}
